Python, get the value of self.request.get() inside __init__ - python

I wanted to get the values of self.request.get('foo') and etal everytime I create an instance of a class, so I decided to use __init__ constructor. Here's my code:
class archive(handler):
d = dict(title='',author= '')
def __init__(self):
self.d['title'] = self.request.get('title')
self.d['author'] = self.request.get('author')
class compose(handler):
def get(self):
self.render('compose.html')
def post(self):
a = archive()
My purpose is, to get rid the repetition of:
title = self.request.get('title')
author = self.request.get('author')
in every def post(self). But the problem is I get a NoneType error:
AttributeError: 'NoneType' object has no attribute 'get'
Obviously, self.request.get('title') returned None. I am just new with Python and Google Appengine.
Thank you guys.

This is how I managed to fix the problem:
class Archive(object):
d = dict(title='',author= '')
def load_d(self):
r = webapp2.get_request()
self.d['title'] = r.get('title')
self.d['author'] = r.get('author')
class Compose(Handler):
def get(self):
self.render('compose.html')
def post(self):
a = Archive()
a.load_d()

I assume you use webapp2.
Your init overrides the init of the webapp2 request handler (super). You can read in the webapp2 docs how to to this:
http://webapp-improved.appspot.com/guide/handlers.html#overriding-init
Take care when you use variables (self.variable) because you can also override variables of the request handler. You can use the request registry.

Related

How can I pass data into a class in python?

I am using django to create a blog editing page. However, my struggles do not involve django, rather just python. I have a class:
class EditForm(forms.Form):
def __init__(self, initcontent):
self.initcontent = initcontent
title = forms.CharField(max_length=100, label='Post Title')
short_description = forms.CharField(widget=forms.Textarea(attrs={"rows":3, "cols":100}))
content = forms.CharField(widget=CKEditorWidget(), initial=Post.objects.get(pk=initcontent).content)
and I am initialising it like this:
form = EditForm()
form.initcontent = post.pk
however I get the error:
File "C:\Users\Rayyan Admin\Documents\GitHub\shaista-s-cooking-blog\blogger\forms.py", line 34, in EditForm
content = forms.CharField(widget=CKEditorWidget(), initial=Post.objects.get(pk=initcontent).content)
NameError: name 'initcontent' is not defined
How do i pass initcontent into the class?
Hi your indenting is off so I'm not sure if that's a mistake in formatting here or causing issues with your code.
Anyways I think what you want is:
class EditForm():
def __init__(self, initcontent):
self.initcontent = initcontent
form = EditForm(post.pk)
Whenever you make an instance of a class, you can pass your data into it if you have defined a constructor. That is the role of a constructor. In your case, you have defined a constructor with initcontent as a parameter. So you can do it like this -
form = EditForm(whatever you need to pass)
This will do.

Accessing parent class variable from an inner class?

I am working with locust and I am working in mimicking the behavior of a user. However I am getting trouble accessing the parent class variable. Any idea how I can pass it?
class User(TaskSet):
some_user = ''
def on_start(self):
self.get_user()
def get_user(self):
some_user = self.client.get...#gets user
#task
class UpdatingUser(TaskSet):
def updating(self):
path = "/posts/" + User.some_user
By the time I get to User.some_user I never have the user.
You've not provided all of the code, but the problem may be that get_user() is setting some_user as an instance attribute somewhere, as in self.some_user = foo.
This will only set some_user for that specific instance of User however (so for Bob, Lisa, Beto, User53, etc.), but not for the User class itself. When accessing some_user with self, as in self.some_user, you set it for the specific instance that's executing those statements, not the class. In updating() you're accessing the class attribute User.some_user, not a specific instance attribute like usr53.some_user. In order to update the class attribute, invariant by default for all instances of User, you ought to be setting it with User.some_user = foo in get_user().
Right now in path = "/posts/" + User.some_user, it's trying to access the class attribute which may never have been set. Because nested classes like UpdatingUser can't access the instances of the nesting class (User) that they're called from, UpdatingUser won't be able to access any some_user set with self or any other instance attributes of User. So the solution would be to have get_user() set the class attribute instead of the instance attribute as described in the previous paragraph.
This answer is a bit late but, if anyone has this issue, the TaskSet has a parent property, which can be used to access the parent's instance variables. The following is what I used for a basic one-time login:
class UserBehaviour(TaskSet):
def on_start(self):
self.token = self.login()
self.headers = {'Authorization': 'Bearer ' + self.token}
def login(self):
with self.client.post("/login", catch_response = True) as response:
return response.json()['token']
#task
class UserTask1(TaskSet):
#task
def get_data(self):
self.client.get("/data", headers = self.parent.headers)
class WebsiteUser(HttpLocust):
task_set = UserBehaviour

AttributeError: can't set attribute

I am working on a legacy django project, in there 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 mainly created so that they could use it to perform assertions in the unit tests .i.e they are not using django.test.Client to test the views but rather they create a mock request and pass that to view as(calling the view as a callable) in the 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 half way through the test suite(quite a huge test suite), some tests begin blowing up when executing the
return Response('some_template.html', RequestContext(request, {'some keys': 'some values'}))
and the stack trace is
self.template = template
AttributeError: can't set attribute
the full stack trace looks something like
======================================================================
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
the actual failing test is
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 the show 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'}))
This answer doesn't address the specifics of this question, but explains the underlying issue.
This specific exception "AttributeError: can't set attribute" is raised (see source) when the attribute you're attempting to change is actually a property that doesn't have a setter. If you have access to the library's code, adding a setter would solve the problem.
EDIT: updated source link to new location in the code.
Edit2:
Example of a setter:
class MAMLMetaLearner(nn.Module):
def __init__(
self,
args,
base_model,
inner_debug=False,
target_type='classification'
):
super().__init__()
self.args = args # args for experiment
self.base_model = base_model
assert base_model is args.model
self.inner_debug = inner_debug
self.target_type = target_type
#property
def lr_inner(self) -> float:
return self.args.inner_lr
#lr_inner.setter
def lr_inner(self, new_val: float):
self.args.inner_lr = new_val
It looks like you don't use self.template in Response class. Try like this:
class Response(HttpResponse):
def __init__(self, template='', calling_context='' status=None):
HttpResponse.__init__(self, get_template(template).render(calling_context), status)
I took a look to django source code I've no idea where template or templates attribute come from in HttpResponse. But I can propose to you to change your test approach and migrate to mock framework. You can rewrite your test like:
#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 your Response() class by a MagicMock() and pass it to your test method as mock_resp variable. You can also use patch as context manager by with construct but decorators are the cleaner way to do it. I don't know if Response is just a stub class for testing but in that case you can patch directly HttpResponce, but it depends from your code.
You can find details about call_args here. Maybe you need to use spec attribute because django make some type checking... but try with and without it (I'm not a django expert). Explore mock framework: it'll give to you lot of powerful tools to make simple tests.

When to use __init__ when creating a class

After using Django for a while, I got use to using classes without def __init__(self): ... when declaring variables. I used to declare my variables in the __init__ function, I now realize that there are cases where don't need to, I'm just unclear on when to use it or not. It seems there is a problem when trying to pass a class to a variable, should I use init in these cases?
I know I could just use __init__ for all cases, but it just makes my short classes like cleaner without it, so I would like to know when I can and cannot use it.
example:
class BaseScraper(object):
# whithout __init__, passing Site() to site wont work.
# site = Site()
# parser = None
def __init__(self):
self.site = Site()
self.parser = None
class Site(object):
# no trouble declaring url as a str
url = ""
def set(self, url):
self.url = url
def get(self):
return self.url
if __name__ == "__main__":
scraper = BaseScraper()
scraper.site.set('http://www.google.com')
print scraper.site.get()
Attributes declared in the class are owned by the class rather than by individual instances of the class. In your site example, url is no more a property of individual Site objects than set or get are. For this kind of example, you want instance data - which you can initialize in __init__.
Python: Difference between class and instance attributes has a good discussion of the differences.
This fails because Site class is not defined yet.
And (as #Peter DeGlopper) said, there is a big difference between class variables and instance variables.
class BaseScraper(object):
# This fails!
site = Site()
parser = None
class Site(object):
# no trouble declaring url as a str
url = ""
def set(self, url):
self.url = url
def get(self):
return self.url
When the virtual machine compile a python module, read and compile everything in class declaration, but on method declaration (like def __init__(...):) only read this line, ignoring the method body.
Example:
class Foo(object):
bar1 = "bar"
foo1 = "foo"
def __init__(self):
self.bar2 = "BAZ"
foo = Foo #Put a class in a veriable? yes, you can.
foo.bar1 # returns "bar"
foo.foo1 # returns "foo"
foo.bar2 # fails!!!! This will be a instance variable, but doesn't exist yet
foo2 = Foo() # Here the __init__ is called
foo2.bar2 # returns "BAZ"
foo2.bar1 #Returns "bar" because all class variables are availables from instances
Hope this helps =)

Call external function without sending 'self' arg

I'm writing tests for a Django application and using a attribute on my test class to store which view it's supposed to be testing, like this:
# IN TESTS.PY
class OrderTests(TestCase, ShopTest):
_VIEW = views.order
def test_gateway_answer(self):
url = 'whatever url'
request = self.request_factory(url, 'GET')
self._VIEW(request, **{'sku': order.sku})
# IN VIEWS.PY
def order(request, sku)
...
My guess is that the problem I'm having is caused because since I'm calling an attribute of the OrderTests class, python assumes I wanna send self and then order get the wrong arguments. Easy to solve... just not use it as a class attribute, but I was wondering if there's a way to tell python to not send self in this case.
Thanks.
This happens because in Python functions are descriptors, so when they are accessed on class instances they bind their first (assumed self) parameter to the instance.
You could access _VIEW on the class, not on the instance:
class OrderTests(TestCase, ShopTest):
_VIEW = views.order
def test_gateway_answer(self):
url = 'whatever url'
request = self.request_factory(url, 'GET')
OrderTests._VIEW(request, **{'sku': order.sku})
Alternatively, you can wrap it in staticmethod to prevent it being bound to the instance:
class OrderTests(TestCase, ShopTest):
_VIEW = staticmethod(views.order)
def test_gateway_answer(self):
url = 'whatever url'
request = self.request_factory(url, 'GET')
self._VIEW(request, **{'sku': order.sku})

Categories

Resources