diff --git a/docs/tasksets.rst b/docs/tasksets.rst index 2c04467420..a5e70979ff 100644 --- a/docs/tasksets.rst +++ b/docs/tasksets.rst @@ -163,7 +163,7 @@ For example, the following code will request URLs /1-/4 in order, and then repea self.client.get("/1") self.client.get("/2") - # you can still use the tasks property to specify a list of tasks + # you can still use the tasks attribute to specify a list of tasks tasks = [function_task] @task diff --git a/docs/writing-a-locustfile.rst b/docs/writing-a-locustfile.rst index 30a93c621d..1e1c49d939 100644 --- a/docs/writing-a-locustfile.rst +++ b/docs/writing-a-locustfile.rst @@ -205,7 +205,7 @@ classes. Say for example, web users are three times more likely than mobile user ... Also you can set the :py:attr:`fixed_count ` attribute. -In this case the weight property will be ignored and the exact count users will be spawned. +In this case the weight attribute will be ignored and the exact count users will be spawned. These users are spawned first. In the example below, only one instance of AdminUser will be spawned, to make some specific work with more accurate control of request count independently of total user count. diff --git a/locust/argument_parser.py b/locust/argument_parser.py index f5b3ca1391..2090b6a1a0 100644 --- a/locust/argument_parser.py +++ b/locust/argument_parser.py @@ -439,12 +439,12 @@ def setup_parser_arguments(parser): other_group.add_argument( "--show-task-ratio", action="store_true", - help="Print table of the User classes' task execution ratio. Use this with non-zero --user option if some classes define non-zero fixed_count property.", + help="Print table of the User classes' task execution ratio. Use this with non-zero --user option if some classes define non-zero fixed_count attribute.", ) other_group.add_argument( "--show-task-ratio-json", action="store_true", - help="Print json data of the User classes' task execution ratio. Use this with non-zero --user option if some classes define non-zero fixed_count property.", + help="Print json data of the User classes' task execution ratio. Use this with non-zero --user option if some classes define non-zero fixed_count attribute.", ) # optparse gives you --version but we have to do it ourselves to get -V too other_group.add_argument( diff --git a/locust/clients.py b/locust/clients.py index 85f26b257c..da12e27805 100644 --- a/locust/clients.py +++ b/locust/clients.py @@ -34,7 +34,7 @@ class HttpSession(requests.Session): the methods for making requests (get, post, delete, put, head, options, patch, request) can now take a *url* argument that's only the path part of the URL, in which case the host part of the URL will be prepended with the HttpSession.base_url which is normally inherited - from a User class' host property. + from a User class' host attribute. Each of the methods for making requests also takes two additional optional arguments which are Locust specific and doesn't exist in python-requests. These are: diff --git a/locust/test/test_locust_class.py b/locust/test/test_locust_class.py index fe59016b41..78a42b1306 100644 --- a/locust/test/test_locust_class.py +++ b/locust/test/test_locust_class.py @@ -46,6 +46,8 @@ class MyUser(User): self.assertRaisesRegex(Exception, "No tasks defined on MyTasks.*", l.run) l.tasks = [] self.assertRaisesRegex(Exception, "No tasks defined on MyTasks.*", l.run) + MyTasks.task = object() + self.assertRaisesRegex(Exception, ".*but you have set a 'task' attribute.*", l.run) def test_tasks_missing_from_user_gives_user_friendly_exception(self): class MyUser(User): @@ -53,6 +55,8 @@ class MyUser(User): l = MyUser(self.environment) self.assertRaisesRegex(Exception, "No tasks defined on MyUser.*", l.run) + MyUser.task = object() + self.assertRaisesRegex(Exception, ".*but you have set a 'task' attribute.*", l.run) def test_task_decorator_ratio(self): t1 = lambda l: None diff --git a/locust/test/test_runners.py b/locust/test/test_runners.py index 14b0ee66f8..4dde4dd129 100644 --- a/locust/test/test_runners.py +++ b/locust/test/test_runners.py @@ -2219,7 +2219,7 @@ def my_task(self): ) ) sleep(0.2) - # hearbeat received from two workers so they are active, for fake_client3 HEARTBEAT_DEAD_INTERNAL has been breached, so it will be removed from worker list + # heartbeat received from two workers so they are active, for fake_client3 HEARTBEAT_DEAD_INTERNAL has been breached, so it will be removed from worker list self.assertEqual(0, len(master.clients.missing)) self.assertEqual(2, master.worker_count) master.stop() diff --git a/locust/user/sequential_taskset.py b/locust/user/sequential_taskset.py index 23e9925db9..07c7ed86ff 100644 --- a/locust/user/sequential_taskset.py +++ b/locust/user/sequential_taskset.py @@ -55,7 +55,7 @@ def __init__(self, *args, **kwargs): def get_next_task(self): if not self.tasks: raise LocustError( - "No tasks defined. use the @task decorator or set the tasks property of the SequentialTaskSet" + "No tasks defined. Use the @task decorator or set the 'tasks' attribute of the SequentialTaskSet" ) task = self.tasks[self._task_index % len(self.tasks)] self._task_index += 1 diff --git a/locust/user/task.py b/locust/user/task.py index a3da8d98d2..4ce76ba977 100644 --- a/locust/user/task.py +++ b/locust/user/task.py @@ -395,8 +395,12 @@ def schedule_task(self, task_callable, first=False): def get_next_task(self): if not self.tasks: + if getattr(self, "task", None): + extra_message = ", but you have set a 'task' attribute - maybe you meant to set 'tasks'?" + else: + extra_message = "." raise Exception( - f"No tasks defined on {self.__class__.__name__}. use the @task decorator or set the tasks property of the TaskSet" + f"No tasks defined on {self.__class__.__name__}{extra_message} use the @task decorator or set the 'tasks' attribute of the TaskSet" ) return random.choice(self.tasks) @@ -469,8 +473,12 @@ class DefaultTaskSet(TaskSet): def get_next_task(self): if not self.user.tasks: + if getattr(self.user, "task", None): + extra_message = ", but you have set a 'task' attribute on your class - maybe you meant to set 'tasks'?" + else: + extra_message = "." raise Exception( - f"No tasks defined on {self.user.__class__.__name__}. use the @task decorator or set the tasks property of the User (or mark it as abstract = True if you only intend to subclass it)" + f"No tasks defined on {self.user.__class__.__name__}{extra_message} Use the @task decorator or set the 'tasks' attribute of the User (or mark it as abstract = True if you only intend to subclass it)" ) return random.choice(self.user.tasks)