locust 2.30.1.dev20__tar.gz → 2.30.1.dev25__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/PKG-INFO +1 -1
  2. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/_version.py +2 -2
  3. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/dispatch.py +27 -48
  4. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/pyproject.toml +1 -1
  5. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/LICENSE +0 -0
  6. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/README.md +0 -0
  7. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/__init__.py +0 -0
  8. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/__main__.py +0 -0
  9. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/argument_parser.py +0 -0
  10. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/clients.py +0 -0
  11. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/contrib/__init__.py +0 -0
  12. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/contrib/fasthttp.py +0 -0
  13. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/debug.py +0 -0
  14. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/env.py +0 -0
  15. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/event.py +0 -0
  16. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/exception.py +0 -0
  17. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/html.py +0 -0
  18. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/input_events.py +0 -0
  19. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/log.py +0 -0
  20. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/main.py +0 -0
  21. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/py.typed +0 -0
  22. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/rpc/__init__.py +0 -0
  23. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/rpc/protocol.py +0 -0
  24. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/rpc/zmqrpc.py +0 -0
  25. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/runners.py +0 -0
  26. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/shape.py +0 -0
  27. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/stats.py +0 -0
  28. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/user/__init__.py +0 -0
  29. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/user/inspectuser.py +0 -0
  30. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/user/sequential_taskset.py +0 -0
  31. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/user/task.py +0 -0
  32. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/user/users.py +0 -0
  33. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/user/wait_time.py +0 -0
  34. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/__init__.py +0 -0
  35. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/cache.py +0 -0
  36. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/date.py +0 -0
  37. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/deprecation.py +0 -0
  38. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/directory.py +0 -0
  39. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/exception_handler.py +0 -0
  40. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/load_locustfile.py +0 -0
  41. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/rounding.py +0 -0
  42. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/timespan.py +0 -0
  43. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/util/url.py +0 -0
  44. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/locust/web.py +0 -0
  45. {locust-2.30.1.dev20 → locust-2.30.1.dev25}/pre_build.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: locust
3
- Version: 2.30.1.dev20
3
+ Version: 2.30.1.dev25
4
4
  Summary: Developer-friendly load testing framework
5
5
  Home-page: https://locust.io/
6
6
  License: MIT
@@ -14,7 +14,7 @@ __version_tuple__: VERSION_TUPLE
14
14
  version_tuple: VERSION_TUPLE
15
15
 
16
16
 
17
- __version__ = "2.30.1.dev20"
17
+ __version__ = "2.30.1.dev25"
18
18
  version = __version__
19
- __version_tuple__ = (2, 30, 1, "dev20")
19
+ __version_tuple__ = (2, 30, 1, "dev25")
20
20
  version_tuple = __version_tuple__
@@ -5,7 +5,7 @@ import itertools
5
5
  import math
6
6
  import time
7
7
  from collections import defaultdict
8
- from collections.abc import Generator, Iterator
8
+ from collections.abc import Iterator
9
9
  from heapq import heapify, heapreplace
10
10
  from math import log2
11
11
  from operator import attrgetter
@@ -17,41 +17,31 @@ if TYPE_CHECKING:
17
17
  from locust import User
18
18
  from locust.runners import WorkerNode
19
19
 
20
+ from collections.abc import Generator, Iterable
21
+ from typing import TypeVar
20
22
 
21
- # To profile line-by-line, uncomment the code below (i.e. `import line_profiler ...`) and
22
- # place `@profile` on the functions/methods you wish to profile. Then, in the unit test you are
23
- # running, use `from locust.dispatch import profile; profile.print_stats()` at the end of the unit test.
24
- # Placing it in a `finally` block is recommended.
25
- # import line_profiler
26
- #
27
- # profile = line_profiler.LineProfiler()
23
+ T = TypeVar("T")
28
24
 
29
25
 
30
- def _kl_generator(users: list[tuple[type[User], float]]) -> Iterator[str | None]:
26
+ def _kl_generator(users: Iterable[tuple[T, float]]) -> Iterator[T | None]:
31
27
  """Generator based on Kullback-Leibler divergence
32
28
 
33
29
  For example, given users A, B with weights 5 and 1 respectively,
34
30
  this algorithm will yield AAABAAAAABAA.
35
31
  """
36
- if not users:
32
+ heap = [(x * log2(x / (x + 1.0)), x + 1.0, x, name) for name, x in users]
33
+ if not heap:
37
34
  while True:
38
35
  yield None
39
36
 
40
- names = [u[0].__name__ for u in users]
41
- weights = [u[1] for u in users]
42
- generated = weights.copy()
43
-
44
- heap = [(x * log2(x / (x + 1.0)), i) for i, x in enumerate(generated)]
45
37
  heapify(heap)
46
-
47
38
  while True:
48
- i = heap[0][1] # choose element which choosing minimizes divergence the most
49
- yield names[i]
50
- generated[i] += 1.0
51
- x = generated[i]
52
- kl_diff = weights[i] * log2(x / (x + 1.0))
39
+ _, x, weight, name = heap[0]
40
+ # (divergence diff, number of generated elements + initial weight, initial weight, name) = heap[0]
41
+ yield name
42
+ kl_diff = weight * log2(x / (x + 1.0))
53
43
  # calculate how much choosing element i for (x + 1)th time decreases divergence
54
- heapreplace(heap, (kl_diff, i))
44
+ heapreplace(heap, (kl_diff, x + 1.0, weight, name))
55
45
 
56
46
 
57
47
  class UsersDispatcher(Iterator):
@@ -378,35 +368,24 @@ class UsersDispatcher(Iterator):
378
368
  return users_on_workers, user_gen, worker_gen, active_users
379
369
 
380
370
  def _user_gen(self) -> Iterator[str | None]:
381
- fixed_users = {u.__name__: u for u in self._user_classes if u.fixed_count}
382
-
383
- fixed_users_gen = _kl_generator([(u, u.fixed_count) for u in fixed_users.values()])
384
- weighted_users_gen = _kl_generator([(u, u.weight) for u in self._user_classes if not u.fixed_count])
371
+ weighted_users_gen = _kl_generator((u.__name__, u.weight) for u in self._user_classes if not u.fixed_count)
385
372
 
386
- # Spawn users
387
373
  while True:
388
- if self._try_dispatch_fixed:
374
+ if self._try_dispatch_fixed: # Fixed_count users are spawned before weight users.
375
+ # Some peoples treat this implementation detail as a feature.
389
376
  self._try_dispatch_fixed = False
390
- current_fixed_users_count = {u: self._get_user_current_count(u) for u in fixed_users}
391
- spawned_classes: set[str] = set()
392
- while len(spawned_classes) != len(fixed_users):
393
- user_name: str | None = next(fixed_users_gen)
394
- if not user_name:
395
- break
396
-
397
- if current_fixed_users_count[user_name] < fixed_users[user_name].fixed_count:
398
- current_fixed_users_count[user_name] += 1
399
- yield user_name
400
-
401
- # 'self._try_dispatch_fixed' was changed outhere, we have to recalculate current count
402
- if self._try_dispatch_fixed:
403
- current_fixed_users_count = {u: self._get_user_current_count(u) for u in fixed_users}
404
- spawned_classes.clear()
405
- self._try_dispatch_fixed = False
406
- else:
407
- spawned_classes.add(user_name)
408
-
409
- yield next(weighted_users_gen)
377
+ fixed_users_missing = [
378
+ (u.__name__, miss)
379
+ for u in self._user_classes
380
+ if u.fixed_count and (miss := u.fixed_count - self._get_user_current_count(u.__name__)) > 0
381
+ ]
382
+ total_miss = sum(miss for _, miss in fixed_users_missing)
383
+ fixed_users_gen = _kl_generator(fixed_users_missing) # type: ignore[arg-type]
384
+ # https://mypy.readthedocs.io/en/stable/common_issues.html#variance
385
+ for _ in range(total_miss):
386
+ yield next(fixed_users_gen)
387
+ else:
388
+ yield next(weighted_users_gen)
410
389
 
411
390
  @staticmethod
412
391
  def _fast_users_on_workers_copy(users_on_workers: dict[str, dict[str, int]]) -> dict[str, dict[str, int]]:
@@ -5,7 +5,7 @@ build-backend = "poetry_dynamic_versioning.backend"
5
5
  [tool.poetry]
6
6
  name = "locust"
7
7
  description = "Developer-friendly load testing framework"
8
- version = "2.30.1.dev20"
8
+ version = "2.30.1.dev25"
9
9
  license = "MIT"
10
10
  readme = "README.md"
11
11
  authors = ["Jonatan Heyman", "Lars Holmberg"]
File without changes
File without changes