locust 2.43.5.dev10__tar.gz → 2.43.5.dev19__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 (69) hide show
  1. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/PKG-INFO +1 -1
  2. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/_version.py +2 -2
  3. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/fasthttp.py +4 -1
  4. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/stats.py +41 -3
  5. locust-2.43.5.dev10/locust/webui/dist/assets/src-DAUMGNLx.js → locust-2.43.5.dev19/locust/webui/dist/assets/src-lBIzfjkZ.js +24 -24
  6. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/auth.html +1 -1
  7. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/index.html +1 -1
  8. locust-2.43.5.dev19/locust/webui/dist/report.html +124 -0
  9. locust-2.43.5.dev10/locust/webui/dist/report.html +0 -124
  10. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/.gitignore +0 -0
  11. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/LICENSE +0 -0
  12. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/README.md +0 -0
  13. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/hatch_build.py +0 -0
  14. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/__init__.py +0 -0
  15. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/__main__.py +0 -0
  16. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/argument_parser.py +0 -0
  17. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/clients.py +0 -0
  18. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/__init__.py +0 -0
  19. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/dns.py +0 -0
  20. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/milvus.py +0 -0
  21. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/mongodb.py +0 -0
  22. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/mqtt.py +0 -0
  23. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/oai.py +0 -0
  24. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/postgres.py +0 -0
  25. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/qdrant.py +0 -0
  26. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/contrib/socketio.py +0 -0
  27. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/debug.py +0 -0
  28. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/dispatch.py +0 -0
  29. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/env.py +0 -0
  30. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/event.py +0 -0
  31. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/exception.py +0 -0
  32. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/html.py +0 -0
  33. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/input_events.py +0 -0
  34. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/log.py +0 -0
  35. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/main.py +0 -0
  36. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/opentelemetry.py +0 -0
  37. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/py.typed +0 -0
  38. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/rpc/__init__.py +0 -0
  39. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/rpc/protocol.py +0 -0
  40. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/rpc/zmqrpc.py +0 -0
  41. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/runners.py +0 -0
  42. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/shape.py +0 -0
  43. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/user/__init__.py +0 -0
  44. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/user/inspectuser.py +0 -0
  45. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/user/markov_taskset.py +0 -0
  46. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/user/sequential_taskset.py +0 -0
  47. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/user/task.py +0 -0
  48. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/user/users.py +0 -0
  49. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/user/wait_time.py +0 -0
  50. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/__init__.py +0 -0
  51. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/cache.py +0 -0
  52. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/date.py +0 -0
  53. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/deprecation.py +0 -0
  54. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/directory.py +0 -0
  55. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/exception_handler.py +0 -0
  56. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/load_locustfile.py +0 -0
  57. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/rounding.py +0 -0
  58. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/timespan.py +0 -0
  59. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/util/url.py +0 -0
  60. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/web.py +0 -0
  61. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/assets/favicon-dark.png +0 -0
  62. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/assets/favicon-light.png +0 -0
  63. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/assets/graphs-dark.png +0 -0
  64. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/assets/graphs-light.png +0 -0
  65. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/assets/terminal.gif +0 -0
  66. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/assets/testruns-dark.png +0 -0
  67. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/locust/webui/dist/assets/testruns-light.png +0 -0
  68. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/pyproject.toml +0 -0
  69. {locust-2.43.5.dev10 → locust-2.43.5.dev19}/pytest_locust/plugin.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: locust
3
- Version: 2.43.5.dev10
3
+ Version: 2.43.5.dev19
4
4
  Summary: Developer-friendly load testing framework
5
5
  Project-URL: homepage, https://locust.io/
6
6
  Project-URL: repository, https://github.com/locustio/locust
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.43.5.dev10'
22
- __version_tuple__ = version_tuple = (2, 43, 5, 'dev10')
21
+ __version__ = version = '2.43.5.dev19'
22
+ __version_tuple__ = version_tuple = (2, 43, 5, 'dev19')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -10,6 +10,7 @@ import re
10
10
  import socket
11
11
  import time
12
12
  import traceback
13
+ import zlib
13
14
  from base64 import b64encode
14
15
  from contextlib import contextmanager
15
16
  from http.cookiejar import CookieJar
@@ -84,6 +85,7 @@ FAILURE_EXCEPTIONS = (
84
85
  SSLError,
85
86
  Timeout,
86
87
  HTTPConnectionClosed,
88
+ zlib.error,
87
89
  )
88
90
 
89
91
 
@@ -254,7 +256,7 @@ class FastHttpSession:
254
256
 
255
257
  if not allow_redirects:
256
258
  old_redirect_response_codes = self.client.redirect_resonse_codes
257
- self.client.redirect_resonse_codes = []
259
+ self.client.redirect_resonse_codes = frozenset()
258
260
 
259
261
  start_perf_counter = time.perf_counter()
260
262
  # send request, and catch any exceptions
@@ -672,6 +674,7 @@ class LocustUserAgent(UserAgent):
672
674
  response_type = FastResponse
673
675
  request_type = FastRequest
674
676
  valid_response_codes = frozenset([200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 301, 302, 303, 304, 307, 308])
677
+ redirect_resonse_codes = frozenset([301, 302, 303, 307, 308])
675
678
 
676
679
  def __init__(self, client_pool: HTTPClientPool | None = None, **kwargs):
677
680
  super().__init__(**kwargs)
@@ -69,6 +69,8 @@ class StatsEntryDict(StatsBaseDict):
69
69
  class StatsErrorDict(StatsBaseDict):
70
70
  error: str
71
71
  occurrences: int
72
+ first_seen: float | None
73
+ last_seen: float | None
72
74
 
73
75
 
74
76
  class StatsHolder(Protocol):
@@ -705,11 +707,21 @@ class StatsEntry:
705
707
 
706
708
 
707
709
  class StatsError:
708
- def __init__(self, method: str, name: str, error: Exception | str | None, occurrences: int = 0):
710
+ def __init__(
711
+ self,
712
+ method: str,
713
+ name: str,
714
+ error: Exception | str | None,
715
+ occurrences: int = 0,
716
+ first_seen: float | None = None,
717
+ last_seen: float | None = None,
718
+ ):
709
719
  self.method = method
710
720
  self.name = name
711
721
  self.error = error
712
722
  self.occurrences = occurrences
723
+ self.first_seen = first_seen
724
+ self.last_seen = last_seen
713
725
 
714
726
  @classmethod
715
727
  def parse_error(cls, error: Exception | str | None) -> str:
@@ -735,6 +747,10 @@ class StatsError:
735
747
 
736
748
  def occurred(self) -> None:
737
749
  self.occurrences += 1
750
+ now = time.time()
751
+ if self.first_seen is None:
752
+ self.first_seen = now
753
+ self.last_seen = now
738
754
 
739
755
  def to_name(self) -> str:
740
756
  error = self.error
@@ -767,7 +783,14 @@ class StatsError:
767
783
 
768
784
  @classmethod
769
785
  def unserialize(cls, data: StatsErrorDict) -> StatsError:
770
- return cls(data["method"], data["name"], data["error"], data["occurrences"])
786
+ return cls(
787
+ data["method"],
788
+ data["name"],
789
+ data["error"],
790
+ data["occurrences"],
791
+ data.get("first_seen"),
792
+ data.get("last_seen"),
793
+ )
771
794
 
772
795
  def to_dict(self):
773
796
  return {
@@ -775,6 +798,8 @@ class StatsError:
775
798
  "name": self.name,
776
799
  "error": self.parse_error(self.error),
777
800
  "occurrences": self.occurrences,
801
+ "first_seen": self.first_seen,
802
+ "last_seen": self.last_seen,
778
803
  }
779
804
 
780
805
 
@@ -815,7 +840,16 @@ def setup_distributed_stats_event_listeners(events: Events, stats: RequestStats)
815
840
  if error_key not in stats.errors:
816
841
  stats.errors[error_key] = StatsError.unserialize(error)
817
842
  else:
818
- stats.errors[error_key].occurrences += error["occurrences"]
843
+ existing = stats.errors[error_key]
844
+ existing.occurrences += error["occurrences"]
845
+ if incoming_first := error.get("first_seen"):
846
+ existing.first_seen = (
847
+ incoming_first if existing.first_seen is None else min(existing.first_seen, incoming_first)
848
+ )
849
+ if incoming_last := error.get("last_seen"):
850
+ existing.last_seen = (
851
+ incoming_last if existing.last_seen is None else max(existing.last_seen, incoming_last)
852
+ )
819
853
 
820
854
  stats.total.extend(StatsEntry.unserialize(data["stats_total"]))
821
855
 
@@ -988,6 +1022,8 @@ class StatsCSV:
988
1022
  "Name",
989
1023
  "Error",
990
1024
  "Occurrences",
1025
+ "First Seen",
1026
+ "Last Seen",
991
1027
  ]
992
1028
 
993
1029
  self.exceptions_columns = [
@@ -1045,6 +1081,8 @@ class StatsCSV:
1045
1081
  stats_error.name,
1046
1082
  StatsError.parse_error(stats_error.error),
1047
1083
  stats_error.occurrences,
1084
+ format_utc_timestamp(stats_error.first_seen) if stats_error.first_seen is not None else "",
1085
+ format_utc_timestamp(stats_error.last_seen) if stats_error.last_seen is not None else "",
1048
1086
  ]
1049
1087
  )
1050
1088