I followed the Django doc to write tests with assertRaisesMessage() but the problem is the exception itself is raised when executing test (so, the test is not executed).
Note that the exception called is an exception I voluntarily raise in a method of my model (not in the view).
class MyTestCase(TestCase):
def test_invertRewardState_view_fails_notmy_reward(self):
self.client.login(email='gislaine#toto.com', password='azerty')
resp = self.client.get(reverse(invertRewardState, args=(1,)))
self.assertRaisesMessage(
expected_exception=Exception,
expected_message=EXC_NOT_YOURS,
callable_obj=resp)
How Should I use AssertRaisesMessage() to let my test be executed without raising the Exception?
Thanks.
EDIT :
After trying falsetru 1st solution, the problem is still the same. As soon as my test enters in the resp = ... part, view is called, then related model method is called and raises the exception.
the full stack trace :
Traceback (most recent call last):
File "/Users/walt/Code/hellodjango/clientizr/tests.py", line 338, in test_invertRewardState_view_fails_notmy_reward
resp = self.client.get(reverse(invertRewardState, args=('1',)))
File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/test/client.py", line 473, in get
response = super(Client, self).get(path, data=data, **extra)
File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/test/client.py", line 280, in get
return self.request(**r)
File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/test/client.py", line 444, in request
six.reraise(*exc_info)
File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 22, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/walt/Code/hellodjango/clientizr/views.py", line 234, in invertRewardState
reward.invert_reward_state(request.user)
File "/Users/walt/Code/hellodjango/clientizr/models.py", line 606, in invert_reward_state
self.throw_error_if_not_owner_reward(cur_user)
File "/Users/walt/Code/hellodjango/clientizr/models.py", line 587, in throw_error_if_not_owner_reward
raise Exception(EXC_NOT_YOURS)
Exception: Cet objet n'est pas le v\xf4tre
You use assertRaisesMessage as a context manager around the code you expect to fail:
class MyTestCase(TestCase):
def test_invertRewardState_view_fails_notmy_reward(self):
self.client.login(email='gislaine#toto.com', password='azerty')
url = reverse(invertRewardState, args=(1,))
with self.assertRaisesMessage(Exception, EXC_NOT_YOURS):
self.client.get(url)
If you use self.client.get, you will not get an exception directly, but you can check status code.
def test_invertRewardState_view_fails_notmy_reward(self):
self.client.login(email='gislaine#toto.com', password='azerty')
resp = self.client.get(reverse(invertRewardState, args=('1',)))
self.assertEqual(resp.status_code, 500)
self.assertIn(EXC_NOT_YOURS in resp.content)
If you want to get an exception, call the view directly.
def test_invertRewardState_view_fails_notmy_reward(self):
request = HttpRequest()
request.user = User.objects.create(email='gislaine#toto.com') # login
self.assertRaisesMessage(Exception, EXC_NOT_YOURS, invertRewardState, '1')
You can use context manager form as Ned Batchelder suggested.
Related
As a newbie, I am currently trying to add a print button to every existing django admin view of a project.
The goal is to make it not depend on a single model I could resolve manually for printing but every existing model which contains foreign keys to other models an so on.
For simplicity I thought it would be the best to just get the cleaned_data of the form and process it for the pdf.
I alread added the print button, the path url and so on and it will create a pdf file for me.
What I am not able to do is to access the forms cleaned_data from my BaseAdmins (extends the ModelAdmin) class like this:
form = BaseForm(request.POST)
if form.is_valid():
data = form.cleaned_data
It will just give me random kinds of errors, like object has no attribute 'is_bound'
So I think that I am generally wrong with the context where I am trying to get the cleaned_data from the form. Every tutorial I found is just showing how to get the data but not fully resolved if it contains foreign keys and not in which context.
Could you please clear up for me where it would make sense to pass any kind of form data maybe as session data or post body to a print view where I can process it.
Thank you very much for reading, hope I was able to describe my problem, feel free to ask.
Edit
This is the BaseForm I changed variable names for internal reasons:
class BaseForm(ModelForm):
def clean_custom(self):
another_model = self.cleaned_data.get('AnotherModel')
custom_models = self.cleaned_data.get('CustomModel')
custom_models_allowed = CustomModel.objects.filter(AnotherModel=another_model)
custom_models_was_list = True
if not custom_models:
return
if not isinstance(custom_models, Iterable):
custom_models_was_list = False
custom_models = [custom_models]
for custom_model in custom_models:
if another_model and custom_model not in custom_models_allowed:
custom_models_allowed = [custom_model.titel for custom_model in custom_models_allowed]
custom_models_allowed = ', '.join(custom_models_allowed)
raise ValidationError(
f'{custom_model} is not part of {another_model}. For selection: {custom_models_allowed}'
)
if custom_models_was_list:
return custom_models
else:
return custom_models[0]
I'm trying to add cleaned_data in my BaseAdmin class where I have access to request and get the following trace:
AttributeError
AttributeError: type object 'CustomForm' has no attribute 'is_bound'
Traceback (most recent call last)
File ".../.env/lib/python3.9/site-packages/django/contrib/staticfiles/handlers.py", line 65, in __call__
return self.application(environ, start_response)
File ".../.env/lib/python3.9/site-packages/django/core/handlers/wsgi.py", line 141, in __call__
response = self.get_response(request)
File ".../.env/lib/python3.9/site-packages/django/core/handlers/base.py", line 75, in get_response
response = self._middleware_chain(request)
File ".../.env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File ".../.env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File ".../.env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 125, in handle_uncaught_exception
return debug.technical_500_response(request, *exc_info)
File ".../.env/lib/python3.9/site-packages/django_extensions/management/technical_response.py", line 40, in null_technical_500_response
raise exc_value.with_traceback(tb)
File ".../.env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File ".../.env/lib/python3.9/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File ".../.env/lib/python3.9/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File ".../.env/lib/python3.9/site-packages/django/contrib/admin/options.py", line 606, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File ".../.env/lib/python3.9/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
response = view_func(request, *args, **kwargs)
File ".../.env/lib/python3.9/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File ".../.env/lib/python3.9/site-packages/django/contrib/admin/sites.py", line 223, in inner
return view(request, *args, **kwargs)
File ".../admin/base_admin.py", line 203, in change_view
if self.form.is_valid(self.form):
File ".../.env/lib/python3.9/site-packages/django/forms/forms.py", line 185, in is_valid
return self.is_bound and not self.errors
AttributeError: type object 'CustomForm' has no attribute 'is_bound'
This is not a standard question format, you are supposed to give us the code for the piece of code where the error occurs, (i.e. the base_admin.py file) but what you have provided is just 3 lines of it.
But so far I can see you are not checking whether the request is of the type of post or not. Pay attention to the if condition at the beginning of the method
def edit(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = PurposeForm(request.POST)
# check whether it's valid:
if form.is_valid():
for key, value in form.cleaned_data.items():
# etc
I'm following along with a lecture on django testing and this is one of the tests:
def test_invalid_flight_page(self):
max_id = Flight.objects.all().aggregate(Max("id"))["id__max"]
c = Client()
response = c.get(f"/flights/{max_id + 1}")
self.assertEqual(response.status_code, 404)
When I run manage.py tests it throws an error on this test, essentially saying there is no matching flight:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.......E..
======================================================================
ERROR: test_invalid_flight_page (flights.tests.FlightTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\sarah\Desktop\airline\flights\tests.py", line 68, in test_invalid_flight_page
response = c.get(f"/flights/{max_id + 1}")
File "C:\Python\Python385\lib\site-packages\django\test\client.py", line 732, in get
response = super().get(path, data=data, secure=secure, **extra)
File "C:\Python\Python385\lib\site-packages\django\test\client.py", line 393, in get
return self.generic('GET', path, secure=secure, **{
File "C:\Python\Python385\lib\site-packages\django\test\client.py", line 470, in generic
return self.request(**r)
File "C:\Python\Python385\lib\site-packages\django\test\client.py", line 709, in request
self.check_exception(response)
File "C:\Python\Python385\lib\site-packages\django\test\client.py", line 571, in check_exception
raise exc_value
File "C:\Python\Python385\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Python\Python385\lib\site-packages\django\core\handlers\base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\sarah\Desktop\airline\flights\views.py", line 21, in flight
flight = Flight.objects.get(pk=flight_id)
File "C:\Python\Python385\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Python\Python385\lib\site-packages\django\db\models\query.py", line 429, in get
raise self.model.DoesNotExist(
flights.models.Flight.DoesNotExist: Flight matching query does not exist.
----------------------------------------------------------------------
Ran 10 tests in 0.120s
FAILED (errors=1)
Destroying test database for alias 'default'...
But that is the point, there is no flight with that id so the response status code for that request should equal 404. As far as I can see I have copied the code accurately from the lecture but the lecturer's tests are all running okay. Can anyone see what I may be missing?
When I change the expected response.status_code to 200 self.assertEqual(response.status_code, 200) it gives me the same error so this indicates to me that the main problem lies with the response line?
Please let me know if there is anything more you need to see.
Your view class is not handling when the query resolves to nothing. In django it's done as follows:
try:
result = SomeModel.objects.get(pk=some_id)
except SomeModel.DoesNotExist:
# Return 404 here
I've met the same problem. Indeed, it came from the response line or client.get() method itself. In my case, I add "/" at the end of the quotation mark as:
response = c.get(f"/flights/{max_id + 1}/")
And then check assert condition. Now it functions as I want.
Also found that:
If you substitute a word instead of a number as an invalid page, it works just fine. For example:
THIS ONE OK (404 were detected):
response = c.get(f"/flights/whatever")
THIS ONE DOESN'T WORK (404 were not detected and errors were alerted):
response = c.get(f"flights/15")
I have defined the following function inside a class in python, where I'm trying to compile python code from external source.
The python code comes in, is written to a file and then the file is sent to the below function.
When I'm trying to call the function as:
self._check_code_for_errors(source_file)
It does not execute the except block, where I'm catching the SyntaxError exception.
def _check_code_for_errors(self, source_file):
try:
file_ = open(source_file.name, 'r')
py_compile.compile(file_.name)
except SyntaxError:
return {'errors': 'You have a problem in your syntax'}
except (OSError, IOError):
return {'errors': 'Some error has occurred, please try again'}
Update:
class ValidatePythonCodeViewSet(generics.CreateAPIView):
parser_classes = (PlainTextParser, )
"""
The view set below accepts code from post request, executes it and then
returns the appropriate results (error or output)
"""
def _write_code_to_file(self, source):
# file is a reserved word in python 2.x, so using file_
with open('tempPythonCode.py', 'w') as file_:
file_.write(source)
return file_
def _check_code_for_errors(self, source_file):
try:
file_ = open(source_file.name, 'r')
py_compile.compile(file_.name, doraise=True)
except py_compile.PyCompileError:
return {'errors': 'You have a problem in your syntax'}
def post(self, request, *args, **kwargs):
source = request.data
if not source:
raise InformationMissingInRequestError()
else:
source_file = self._write_code_to_file(source)
response = self._check_code_for_errors(source_file)
if response.get('errors', None):
return Response(response, status=status.HTTP_400_BAD_REQUEST)
else:
#execute code here and return
pass
return Response(response, status=status.HTTP_200_OK)
The request that I'm making is:
TraceBack
File "tempPythonCode.py", line 1
import os\nprint 'hi
^
SyntaxError: unexpected character after line continuation character
Internal Server Error: /api/python/
Traceback (most recent call last):
File "/home/dhruuv/.virtualenvs/pythoneval/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/home/dhruuv/.virtualenvs/pythoneval/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/dhruuv/.virtualenvs/pythoneval/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/home/dhruuv/.virtualenvs/pythoneval/local/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/home/dhruuv/.virtualenvs/pythoneval/local/lib/python2.7/site-packages/rest_framework/views.py", line 466, in dispatch
response = self.handle_exception(exc)
File "/home/dhruuv/.virtualenvs/pythoneval/local/lib/python2.7/site-packages/rest_framework/views.py", line 463, in dispatch
response = handler(request, *args, **kwargs)
File "/home/dhruuv/projects/PythonEval/api/views.py", line 44, in post
if response.get('errors', None):
AttributeError: 'NoneType' object has no attribute 'get'
[10/Feb/2016 09:45:44] "POST /api/python/ HTTP/1.1" 500 87401
Update 2
I tried it in ipdb, which worked just fine!
In [5]: try:
py_compile.compile('testing.py', doraise=True)
except py_compile.PyCompileError:
print 'dfsssssssssssss'
...:
dfsssssssssssss
Any help is appreciated.
SyntaxError is not a runtime error, and you cannot catch it in code. However, py_compile does not raise SyntaxError; as the documentation shows, it raises py_compile.PyCompileError.
Edit So there are a couple of things wrong with your code here. Firstly, again as the documentation shows, you need to pass doraise=True to compile in order to get it to raise an error.
And the other exception is happening because you're not returning anything from _check_code_for_errors if it succeeds. You probably should return an empty dict.
I have written a unit test to test an api....Its a GET call....
When I run it , i get this error ...Heres the traceback....
Traceback (most recent call last):
File "/home/arindam31/XXX-Name/mapi/tests.py", line 141, in test_get_cities
response = self.cl.get('/mapi/latest/cities/')
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 445, in get
response = super(Client, self).get(path, data=data, **extra)
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 229, in get
return self.request(**r)
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 387, in request
response = self.handler(environ)
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 84, in __call__
response = self.get_response(request)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 169, in get_response
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 218, in handle_uncaught_exception
return callback(request, **param_dict)
File "/home/arindam31/XXX-Name/saul/views.py", line 546, in do_handle_500
return render_to_response("500.html", context_instance=RequestContext(request))
File "/usr/local/lib/python2.7/dist-packages/django/template/context.py", line 177, in __init__
self.update(processor(request))
File "/home/arindam31/XXX-Name/saul/context_processors.py", line 46, in common_context
ret_dict['city'] = request.city
AttributeError: 'WSGIRequest' object has no attribute 'city'
Heres my unit test...
def test_get_cities(self):
request = HttpRequest()
request.city = self.c1
response = self.cl.get('/mapi/latest/cities/')
content = response.content
data = json.loads(content)
for city in City.objects.all():
assert city.name in data
assert data[city.name] == city.pk
Here , self.c1 is a city type object in the setUp part....HttpRequest is from django.http.
The view being tested is below:
def get_cities(request):
print "1"
if ENABLE_HTTPS_CHECK and not request.is_secure():
return HttpResponseForbidden()
if request.method != 'GET':
return HttpResponseNotAllowed('Not allowed')
city_map = _get_city_map()
response = HttpResponse(json.dumps(city_map)
content_type='application/json')
response['Cache-Control'] = 'no-cache'
return response
If you want to test your view with your own request object, you should call the view directly. You should use the RequestFactory to create your request.
As Daniel Roseman points out your request object having a city attribute remains broken, unless you have some middleware that would set it. You clearly have some middleware that require it to be set in saul/context_processors.py.
Using RequestFactory and calling the view directly circumvents the middleware entirely, so you can concentrate on testing your view (if the view supports the absent middleware).
If your view requires the middelware to be operational, you probably just need to be logged in using the test client. It has a session pr test method.
I have no idea what you are trying to do here. You instantiate a request object, assign a city attribute, then proceed to ignore that object and just use the standard test client. I don't know why you would think that that request would be used for the client get.
To be honest though I think that your entire design is broken. You don't show how you expect to get the parameter into the request in a normal non-test scenario, but usually you would pass it via the POST or GET parameters rather than annotating it into the request somehow. That would of course make it easier to test, since you could just pass the dictionary to the client call.
I'm using the #login_required decorator in my project since day one and it's working fine, but for some reason, I'm starting to get "
AttributeError: 'unicode' object has no attribute 'user' " on some specific urls (and those worked in the past).
Example : I am the website, logged, and then I click on link and I'm getting this error that usually is linked to the fact that there is no SessionMiddleware installed. But in my case, there is one since I am logged on the site and the page I am on also had a #login_required.
Any idea?
The url is definied as : (r'^accept/(?P<token>[a-zA-Z0-9_-]+)?$', 'accept'),
and the method as : #login_required
def accept(request,token): ...
The Traceback:
Traceback (most recent call last):
File "/Users/macbook/virtualenv/proj/lib/python2.6/site-packages/django/core/servers/basehttp.py", line 674, in __call__
return self.application(environ, start_response)
File "/Users/macbook/virtualenv/proj/lib/python2.6/site-packages/django/core/handlers/wsgi.py", line 241, in __call__
response = self.get_response(request)
File "/Users/macbook/virtualenv/proj/lib/python2.6/site-packages/django/core/handlers/base.py", line 141, in get_response
return self.handle_uncaught_exception(request, resolver, sys.exc_info())
File "/Users/macbook/virtualenv/proj/lib/python2.6/site-packages/django/core/handlers/base.py", line 165, in handle_uncaught_exception
return debug.technical_500_response(request, *exc_info)
File "/Users/macbook/virtualenv/proj/lib/python2.6/site-packages/django/core/handlers/base.py", line 100, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/Users/macbook/virtualenv/proj/lib/python2.6/site-packages/django/contrib/auth/decorators.py", line 25, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/macbook/dev/pycharm-projects/proj/match/views.py", line 33, in accept
return __process(token,callback)
File "/Users/macbook/virtualenv/proj/lib/python2.6/site-packages/django/contrib/auth/decorators.py", line 24, in _wrapped_view
if test_func(request.user):
AttributeError: 'unicode' object has no attribute 'user'`
The decorator was on a private method that doesn't have the request as a parameter. I removed that decorator (left there because of a refactoring and lack of test [bad me]).
Problem solved.
This can also happen if you call a decorated method from another method without providing a request parameter.