AttributeError: cannot set attribute

I am working on an old django project, somewhere there is a class defined as follows:

from django.http import HttpResponse class Response(HttpResponse): def __init__(self, template='', calling_context='' status=None): self.template = template self.calling_context = calling_context HttpResponse.__init__(self, get_template(template).render(calling_context), status) 

and this class is used in views as follows

 def some_view(request): #do some stuff return Response('some_template.html', RequestContext(request, {'some keys': 'some values'})) 

this class was created mainly so that they could use it to execute statements in unit tests. They do not use django.test.Client to check the views, but instead they create a request layout and pass it to view as (calling the view as called) in tests as follows

 def test_for_some_view(self): mock_request = create_a_mock_request() #call the view, as a function response = some_view(mock_request) #returns an instance of the response class above self.assertEquals('some_template.html', response.template) self.assertEquals({}, response.context) 

The problem is that halfway through the test suite (a fairly large test suite) some tests begin to explode when executed

 return Response('some_template.html', RequestContext(request, {'some keys': 'some values'})) 

and stack trace

 self.template = template AttributeError: can't set attribute 

A full stack trace looks something like this:

 ====================================================================== ERROR: test_should_list_all_users_for_that_specific_sales_office ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/austiine/Projects/mped/console/metrics/tests/unit/views/sales_office_views_test.py", line 106, in test_should_list_all_users_for_that_specific_sales_office response = show(request, sales_office_id=sales_office.id) File "/Users/austiine/Projects/mped/console/metrics/views/sales_office_views.py", line 63, in show "sales_office_users": sales_office_users})) File "/Users/austiine/Projects/mped/console/metrics/utils/response.py", line 9, in __init__ self.template = template AttributeError: can't set attribute 

actual verification failure

 def test_should_list_all_users_for_that_specific_sales_office(self): user_company = CompanyFactory.create() request = self.mock_request(user_company) #some other stuff #calling the view response = show(request, sales_office_id=sales_office.id) self.assertIn(user, response.calling_context["sales_office_users"]) self.assertNotIn(user2, response.calling_context["sales_office_users"]) 

code for presentation view

 def show(request, sales_office_id): user = request.user sales_office = [] sales_office_users = [] associated_market_names = [] try: sales_office = SalesOffice.objects.get(id=sales_office_id) sales_office_users = User.objects.filter(userprofile__sales_office=sales_office) associated_market_names = Market.objects.filter(id__in= (sales_office.associated_markets.all())).values_list("name", flat=True) if user.groups.all()[0].name == UserProfile.COMPANY_AO: associated_market_names = [market.name for market in sales_office.get_sales_office_user_specific_markets(user)] except: pass return Response("sales_office/show.html", RequestContext(request, {'keys': 'values'})) 
+6
source share
3 answers

This answer does not address the features of this question, but explains the underlying problem. This particular exception, "AttributeError: Unable to Set Attribute," is raised (see source ) when the attribute you are trying to change is actually a property that does not have a setter. If you have access to the library code, adding a setter will solve the problem.

EDIT: Updated source link to a new location in the code.

+18
source

It looks like you are not using self.template in the Response class. Try it like this:

 class Response(HttpResponse): def __init__(self, template='', calling_context='' status=None): HttpResponse.__init__(self, get_template(template).render(calling_context), status) 
0
source

I took a look at the django source code. I have no idea where the template or templates attribute is present in the HttpResponse . But I can suggest you change your test approach and switch to the mock framework. You can rewrite your test as follows:

 @patch("qualified_path_of_response_module.response.Response", spec=Response) def test_should_list_all_users_for_that_specific_sales_office(self,mock_resp): user_company = CompanyFactory.create() request = self.mock_request(user_company) #some other stuff #calling the view response = show(request, sales_office_id=sales_office.id) self.assertTrue(mock_resp.called) context = mock_resp.call_args[0][2] self.assertIn(user, context["sales_office_users"]) self.assertNotIn(user2, context["sales_office_users"]) 

@patch decorator replace the Response() class with MagicMock() and pass it to your test method as the mock_resp variable. You can also use patch as a context manager with , but decorators are a cleaner way to do this. I donโ€™t know if Response just a stub class for testing, but in this case you can install the fix directly with HttpResponce , but it depends on your code.

Read more about call_args here . You might need to use the spec attribute because django does some type checking ... but try with it without it (I'm not a django expert). Explore the mock framework: it will provide you with many powerful tools for simple tests.

0
source

Source: https://habr.com/ru/post/979386/


All Articles