2

entry_point.py

from other_file import UserBehaviour

class ApiUser(HttpUser):

  tasks = [UserBehaviour]

  def on_start(self):
    # log in and return session id and cookie
    # example: self.foo = "foo"

other_file.py

from entry_point import ApiUser

class UserBehaviour(TaskSet):

  @task
  def do_something(self, session_id, session_cookie)
    # use session id and session cookie from user instance running the taskset
    # example: print(self.ApiUser.foo)

NOTE: Going through the documentation, I did find that "the User instance can be accessed from within a TaskSet instance through the TaskSet.user", however all my attempts to import the user into the taskset file led to a "cannot import name 'ApiUser' from 'entry_point'" error. If instead of from entry_point import ApiUser I do from entry_point import *, then I get a name 'ApiUser' is not defined error.

Xen0byte
  • 89
  • 9
  • Storing your variables on the User is probably the right approach. Can you show the code where you tried that and you got the ”locust.user has no {name}” error? – Cyberwiz Jul 05 '20 at 11:28
  • Hi @Cyberwiz, thanks for the reply. That error was a bit of a red herring. I've realized in the meantime that I was accidentally referencing the actual HttpUser class rather than my user class inheriting from that class. I've updated my question to reflect what I believe to be the real problem. – Xen0byte Jul 06 '20 at 09:55
  • You cant have two files importing eachother. This creates a circular dependency. – Cyberwiz Jul 06 '20 at 16:17
  • @Cyberwiz Yeah, I was pretty sure that's the problem. So how would other locust users accomplish what I'm trying to achieve? It feels like a fairly common scenario to need data from the user running the tasksets so I'm surprised there aren't more questions about this. Most of the answers I've found say to just keep all the tasks in a single file but that just becomes unmanageable at some point. – Xen0byte Jul 06 '20 at 17:15
  • You dont need to import the User in your taskset file. You can reference the user instance with self.user. So use self.user.foo instead of self.ApiUser.foo in your example. – Cyberwiz Jul 06 '20 at 17:22
  • @Cyberwiz I just had a thought; I'm going to try importing ApiUser inside the class, maybe that will work. – Xen0byte Jul 06 '20 at 17:23
  • @Cyberwiz Regarding your previous comment, that's what I tried initially and I got the "locust.user has no 'foo' attribute" error. I'll give this another go, maybe I've done something wrong before. – Xen0byte Jul 06 '20 at 17:24
  • No, that wont work and even if it did, it wouldnt do the right thing. You can only import your User CLASS, not the User INSTANCE. – Cyberwiz Jul 06 '20 at 17:25
  • @Cyberwiz Ah, yes, that makes all the sense in the world. I was being a tad overly-optimistic hoping it would somehow magically work after solving the import problem. – Xen0byte Jul 06 '20 at 17:28

1 Answers1

1

Thank you very much @Cyberwiz for putting me on the right track. I've finally managed to figure out what I was doing wrong... which, as it turns out, was a couple of things.

Firstly, importing ApiUser in other_file.py was incorrect for two reasons: 1) it creates a cyclical dependency, and 2) even if it would eventually work it would import the ApiUser class, not the instance of the ApiUser class.

Secondly, I was previously getting a module locust.user has no attribute {name} error, and that was because my code looked like this:

class UserBehaviour(TaskSet):
  # do something with user.foo

Having figured this out, I honestly have no idea why I thought the above would work. I've changed my code to reflect the example below and everything now works like a charm:

class UserBehaviour(TaskSet):

  @task
  def do_something(self):
    # do something with self.user.foo
Xen0byte
  • 89
  • 9
  • Great that you got it to work :) But what is the "from locust import user" for? (in your corrected solution I mean) (and even if it is needed for something later on, why "user" and not "User"?) – Cyberwiz Jul 06 '20 at 18:18
  • @Cyberwiz Having navigated to the definitions of both in an effort to understand a little better how the framework works, `User` is the parent of `HttpUser`, and it's declared in `locust.users`; this is the base class of all locust users. On the other hand, `user` is declared in `locust.user.task`; it is decorated with `property` and it is the instance of the user that the current taskset was created by. – Xen0byte Jul 06 '20 at 18:38
  • Aha, ok! At first I didnt even understand why that import would even work! I guess you could just remove that line from the corrected solution then? – Cyberwiz Jul 06 '20 at 18:48
  • 1
    Spot on again, that `user` import is unnecessary. – Xen0byte Jul 07 '20 at 08:32