Accessing parent class variable from an inner class? - python

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

Related

Mock instance created from class stored in variable

I have the following code:
class Messenger(object):
def __init__(self):
# Class Type of what messages will be created as.
message_class = Message
def publish(self, body):
# Instantiate object of type stored in `message_class`
message = message_class(body)
message.publish()
I want to assert that the Message.publish() method is called. How do I achieve this?
I've already tried the following ways:
Assign message_class to Mock or Mock(). If I debug what message_class(body) returns, it is a Mock, but I don't seem to be able to get the instance and assert it (because the Mock I assign in my test is not the instance used, it is the Type).
Patch Message class with decorator. Whenever I do this it seems like it does not catch it. When I debug what message_class(body) returns its of Message type, not Mock.
Try to mock the __init__ method of message_class in hopes that I can set the instance that is returned whenever the code tries to Instantiate the message. Does not work, throws errors because the __init__ method is not suppose to have a return value.
If you were storing the actual instance, I'd say you could do something like messenger.message.publish.assert_called_once, but since message_class is being stored, it makes it slightly trickier. Given that, you can pull the return_value from the mocked class and check the call that way. Here's how I did it:
Messenger. Note the slight modification to assign message_class to self. I'm assuming you meant to do that, otherwise it wouldn't work without some global funkiness:
'''messenger.py'''
class Message(object):
def __init__(self, body):
self.body = body
def publish(self):
print('message published: {}'.format(self.body))
class Messenger(object):
def __init__(self):
# Class Type of what messages will be created as.
self.message_class = Message
def publish(self, body):
# Instantiate object of type stored in `message_class`
message = self.message_class(body)
message.publish()
Test:
'''test_messenger.py'''
from unittest import mock, TestCase
from messenger import Messenger
class TestMessenger(TestCase):
#mock.patch('messenger.Message')
def test_publish(self, mock_message):
messenger = Messenger()
messenger.publish('test body')
# .return_value gives the mock instance, from there you can make your assertions
mock_message.return_value.publish.assert_called_once()

Class instance as class variable in python

I am making a class which I would like to have as a class member of a separate class so that all instances of this second class can access the first class. At the moment I have something which looks like this:
class A:
def __init__(self):
print "In Constructor!"
class B:
ClassA = ''
def __init__(self, InstanceA):
self.ClassA = InstanceA
However, I get complaints saying "str object has no attribute..." when I try and use the ClassA class variable. Is there a way to construct class B with an argument of InstanceA and then somehow set it to be a class variable? Or any other solution for that matter!
You are not assigning the class attribute in B.__init__, just setting a new instance attribute - B.ClassA is still '' (None would be a more sensible starting value, by the way).
The minimal fix is:
class B:
ClassA = None
def __init__(self, InstanceA):
self.__class__.ClassA = InstanceA # or B.ClassA = ...
However, note that this changes the class attribute every time you create a new instance.
Based on your comments, something like this may be more helpful:
class B:
ClassA = None
#classmethod
def set_class_attr(cls, instance):
cls.ClassA = instance
Which you can then use like:
B.set_class_attr(A()) # set class attribute once
b = B() # don't need to pass in new A instances when creating B instances
b.ClassA. # ...
Depending on the behaviour you want, you can check in that classmethod whether the instance has already been set and e.g. raise an error if the user tries to reset it.

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 =)

Python 3 static members

I am trying to achieve the following:
class A:
username = None
username = get_username()
def get_username(self):
if username is None:
try:
uname = os.environ["USER"]
except:
printf("Couldn't find a user name")
return uname
return username
Not sure how to achieve this. I'm sure I'm missing some "self." prefixes but this is the first time I'm working with python and static members.
In a sense I want a class with some members and functions to calculate values for these members but I don't want recalculations. I would also like these to be static functions and data members.
The problem is that the line "username = get_username()" the function hasn't already been defined. If I put username after the function then it's not
First, there's no reason to assign None to username if you're just going to reassign it immediately after.
Second, if you want the method to be a static method, you can't give it a self argument. And if you want a real static method, you have to declare it explicitly.
#staticmethod
def get_username():
if username is None:
...
Otherwise, you need an instance of the class (that self) to call it on, and you don't have one yet.
In Python 3, any regular method acts like a static method when called on the class, like an instance method when called on an instance. So, if you're sure you're never going to want to call a.get_username() on an instance a, you can skip the decorator. But you still need to get rid of the self parameter.
I think what you're actually trying to do is use a class variable to memoize the result of a static method. You can't do that, but you can use a class variable to memoize the result of a class method, which may be close enough. That would look like this:
class A:
username = None
#classmethod
def get_username(cls):
if cls.username is None:
try:
uname = os.environ["USER"]
except:
print("Couldn't find a user name")
else:
cls.username = uname
return cls.username
On the other hand, there's no good reason username has to be a class member. You can memoize by adding a member to the function, by passing a mutable default variable, or in various other ways which don't require infecting the class, and which allow you to leave get_username as a static method instead of a class method.
But really, the best solution is to find a memoization library on PyPI, in ActiveState's recipe list, etc., so you can just write this:
class A:
#memoize
#staticmethod
def get_username():
try:
return os.environ["USER"]
except:
print("Couldn't find a user name")
return None
Again, you can drop the #staticmethod if you're sure nobody's ever going to try to create an instance of A and call get_username on it.
if you don't want to lose the ability to refer to A.username, you can use class property with a little bit of metaclass:
class A(type):
def __new__(cls, name, bases, attrs):
# this allows B().username to also work
attrs['username'] = property(lambda s: s.__class__.username)
return type.__new__(cls, name, bases, attrs)
#property
def username(self):
if not hasattr(self, '_username'):
self._username = 'bar'
return self._username
class B(object):
__metaclass__ = A
print B.username
print B().username

Accessing Parent Class' Property From Derived Class

I'm new to python and GAE and I thought python will act as any other OO language, but apparently not. How does __init__(self): function gives me different results in the following code?
class BaseHandler(webapp.RequestHandler):
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
user = User.get_by_key_name(cookie["uid"])
return self._current_user
class SubmitHandler(BaseHandler):
template_values = dict(facebook_app_id=FACEBOOK_APP_ID)
def __init__(self):
#throws error : AttributeError: 'SubmitHandler' object has no attribute 'request'
self.template_values['current_user'] = self.current_user
def get(self):
#this one function is error free
self.template_values['current_user'] = self.current_user
How do I access the class' parent property?
If you look at your SubmitHandler class you'll notice that it indeed does not have a request attribute -- at least, none you set, and none you give the parent class a chance to set. Perhaps what you need to do is call the parentclass __init__ method before you try to access self.current_user.
As a side note, you should realize that the template_values dict you define inside the SubmitHandler class there is a class attribute, and thus shared between all instances of the class. Since you assign it something instance-specific in your __init__, you probably mean for it to be an instance attribute instead. Assign it to self.template_values in your __init__ method.
There's nothing particularly different about Python's object inheritance.
By defining __init__, you have told Python that this is all that needs to be done to initialize the object. You're therefore denying it the chance to run the superclass's initialization code. You need to call super:
def __init__(self, *args, **kwargs):
super(SubmitHandler, self).__init__(*args, **kwargs)
self.template_values['current_user'] = self.current_user
This might however not solve your problem - you're failing to take into account the possibility that self.request is initialized at another point in the program, which is why it works by the time get is called.
self.request and self.response are not set by the class constructor in webapp. They're set later, when the framework calls the handler's initialize method. You can override this, just make sure you call the parent class's initialize before doing anything else.

Categories

Resources