From d7ca3507ba771330714a035b605912eda54f0ad8 Mon Sep 17 00:00:00 2001 From: Lars Holmberg Date: Wed, 27 Jul 2022 22:25:12 +0200 Subject: [PATCH 1/4] Stop calling attributes 'properties' in some places. --- docs/tasksets.rst | 2 +- locust/argument_parser.py | 4 ++-- locust/clients.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) 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/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: From 3ed62e0b803b386caba12a1bf14eaf89094b3fff Mon Sep 17 00:00:00 2001 From: Lars Holmberg Date: Wed, 27 Jul 2022 23:25:02 +0200 Subject: [PATCH 2/4] Give a better error message when someone accidentally sets User.task instead of User.tasks --- docs/writing-a-locustfile.rst | 2 +- locust/test/test_locust_class.py | 4 ++++ locust/user/sequential_taskset.py | 2 +- locust/user/task.py | 12 ++++++++++-- 4 files changed, 16 insertions(+), 4 deletions(-) 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/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/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..d8848b865c 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.user, "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) From fedc61dfe8799fcdfe3c46b24aa8072931a1c8dc Mon Sep 17 00:00:00 2001 From: Lars Holmberg Date: Wed, 27 Jul 2022 23:37:29 +0200 Subject: [PATCH 3/4] Fix detection of accidental TaskSet.task attribute --- locust/user/task.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locust/user/task.py b/locust/user/task.py index d8848b865c..4ce76ba977 100644 --- a/locust/user/task.py +++ b/locust/user/task.py @@ -395,7 +395,7 @@ def schedule_task(self, task_callable, first=False): def get_next_task(self): if not self.tasks: - if getattr(self.user, "task", None): + if getattr(self, "task", None): extra_message = ", but you have set a 'task' attribute - maybe you meant to set 'tasks'?" else: extra_message = "." From a5b31f622e59b643d70391e1050319171d6ea980 Mon Sep 17 00:00:00 2001 From: Lars Holmberg Date: Thu, 28 Jul 2022 11:41:20 +0200 Subject: [PATCH 4/4] fix spelling in comment --- locust/test/test_runners.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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()