rasa-pro 3.9.18__py3-none-any.whl → 3.10.16__py3-none-any.whl

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.

Potentially problematic release.


This version of rasa-pro might be problematic. Click here for more details.

Files changed (183) hide show
  1. README.md +0 -374
  2. rasa/__init__.py +1 -2
  3. rasa/__main__.py +5 -0
  4. rasa/anonymization/anonymization_rule_executor.py +2 -2
  5. rasa/api.py +27 -23
  6. rasa/cli/arguments/data.py +27 -2
  7. rasa/cli/arguments/default_arguments.py +25 -3
  8. rasa/cli/arguments/run.py +9 -9
  9. rasa/cli/arguments/train.py +11 -3
  10. rasa/cli/data.py +70 -8
  11. rasa/cli/e2e_test.py +104 -431
  12. rasa/cli/evaluate.py +1 -1
  13. rasa/cli/interactive.py +1 -0
  14. rasa/cli/llm_fine_tuning.py +398 -0
  15. rasa/cli/project_templates/calm/endpoints.yml +1 -1
  16. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  17. rasa/cli/run.py +15 -14
  18. rasa/cli/scaffold.py +10 -8
  19. rasa/cli/studio/studio.py +35 -5
  20. rasa/cli/train.py +56 -8
  21. rasa/cli/utils.py +22 -5
  22. rasa/cli/x.py +1 -1
  23. rasa/constants.py +7 -1
  24. rasa/core/actions/action.py +98 -49
  25. rasa/core/actions/action_run_slot_rejections.py +4 -1
  26. rasa/core/actions/custom_action_executor.py +9 -6
  27. rasa/core/actions/direct_custom_actions_executor.py +80 -0
  28. rasa/core/actions/e2e_stub_custom_action_executor.py +68 -0
  29. rasa/core/actions/grpc_custom_action_executor.py +2 -2
  30. rasa/core/actions/http_custom_action_executor.py +6 -5
  31. rasa/core/agent.py +21 -17
  32. rasa/core/channels/__init__.py +2 -0
  33. rasa/core/channels/audiocodes.py +1 -16
  34. rasa/core/channels/voice_aware/__init__.py +0 -0
  35. rasa/core/channels/voice_aware/jambonz.py +103 -0
  36. rasa/core/channels/voice_aware/jambonz_protocol.py +344 -0
  37. rasa/core/channels/voice_aware/utils.py +20 -0
  38. rasa/core/channels/voice_native/__init__.py +0 -0
  39. rasa/core/constants.py +6 -1
  40. rasa/core/information_retrieval/faiss.py +7 -4
  41. rasa/core/information_retrieval/information_retrieval.py +8 -0
  42. rasa/core/information_retrieval/milvus.py +9 -2
  43. rasa/core/information_retrieval/qdrant.py +1 -1
  44. rasa/core/nlg/contextual_response_rephraser.py +32 -10
  45. rasa/core/nlg/summarize.py +4 -3
  46. rasa/core/policies/enterprise_search_policy.py +113 -45
  47. rasa/core/policies/flows/flow_executor.py +122 -76
  48. rasa/core/policies/intentless_policy.py +83 -29
  49. rasa/core/processor.py +72 -54
  50. rasa/core/run.py +5 -4
  51. rasa/core/tracker_store.py +8 -4
  52. rasa/core/training/interactive.py +1 -1
  53. rasa/core/utils.py +56 -57
  54. rasa/dialogue_understanding/coexistence/llm_based_router.py +53 -13
  55. rasa/dialogue_understanding/commands/__init__.py +6 -0
  56. rasa/dialogue_understanding/commands/restart_command.py +58 -0
  57. rasa/dialogue_understanding/commands/session_start_command.py +59 -0
  58. rasa/dialogue_understanding/commands/utils.py +40 -0
  59. rasa/dialogue_understanding/generator/constants.py +10 -3
  60. rasa/dialogue_understanding/generator/flow_retrieval.py +21 -5
  61. rasa/dialogue_understanding/generator/llm_based_command_generator.py +13 -3
  62. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +134 -90
  63. rasa/dialogue_understanding/generator/nlu_command_adapter.py +47 -7
  64. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +127 -41
  65. rasa/dialogue_understanding/patterns/restart.py +37 -0
  66. rasa/dialogue_understanding/patterns/session_start.py +37 -0
  67. rasa/dialogue_understanding/processor/command_processor.py +16 -3
  68. rasa/dialogue_understanding/processor/command_processor_component.py +6 -2
  69. rasa/e2e_test/aggregate_test_stats_calculator.py +134 -0
  70. rasa/e2e_test/assertions.py +1223 -0
  71. rasa/e2e_test/assertions_schema.yml +106 -0
  72. rasa/e2e_test/constants.py +20 -0
  73. rasa/e2e_test/e2e_config.py +220 -0
  74. rasa/e2e_test/e2e_config_schema.yml +26 -0
  75. rasa/e2e_test/e2e_test_case.py +131 -8
  76. rasa/e2e_test/e2e_test_converter.py +363 -0
  77. rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
  78. rasa/e2e_test/e2e_test_coverage_report.py +364 -0
  79. rasa/e2e_test/e2e_test_result.py +26 -6
  80. rasa/e2e_test/e2e_test_runner.py +493 -71
  81. rasa/e2e_test/e2e_test_schema.yml +96 -0
  82. rasa/e2e_test/pykwalify_extensions.py +39 -0
  83. rasa/e2e_test/stub_custom_action.py +70 -0
  84. rasa/e2e_test/utils/__init__.py +0 -0
  85. rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
  86. rasa/e2e_test/utils/io.py +598 -0
  87. rasa/e2e_test/utils/validation.py +80 -0
  88. rasa/engine/graph.py +9 -3
  89. rasa/engine/recipes/default_components.py +0 -2
  90. rasa/engine/recipes/default_recipe.py +10 -2
  91. rasa/engine/storage/local_model_storage.py +40 -12
  92. rasa/engine/validation.py +78 -1
  93. rasa/env.py +9 -0
  94. rasa/graph_components/providers/story_graph_provider.py +59 -6
  95. rasa/llm_fine_tuning/__init__.py +0 -0
  96. rasa/llm_fine_tuning/annotation_module.py +241 -0
  97. rasa/llm_fine_tuning/conversations.py +144 -0
  98. rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
  99. rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
  100. rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
  101. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
  102. rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
  103. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
  104. rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
  105. rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
  106. rasa/llm_fine_tuning/storage.py +174 -0
  107. rasa/llm_fine_tuning/train_test_split_module.py +441 -0
  108. rasa/model_training.py +56 -16
  109. rasa/nlu/persistor.py +157 -36
  110. rasa/server.py +45 -10
  111. rasa/shared/constants.py +76 -16
  112. rasa/shared/core/domain.py +27 -19
  113. rasa/shared/core/events.py +28 -2
  114. rasa/shared/core/flows/flow.py +208 -13
  115. rasa/shared/core/flows/flow_path.py +84 -0
  116. rasa/shared/core/flows/flows_list.py +33 -11
  117. rasa/shared/core/flows/flows_yaml_schema.json +269 -193
  118. rasa/shared/core/flows/validation.py +112 -25
  119. rasa/shared/core/flows/yaml_flows_io.py +149 -10
  120. rasa/shared/core/trackers.py +6 -0
  121. rasa/shared/core/training_data/structures.py +20 -0
  122. rasa/shared/core/training_data/visualization.html +2 -2
  123. rasa/shared/exceptions.py +4 -0
  124. rasa/shared/importers/importer.py +64 -16
  125. rasa/shared/nlu/constants.py +2 -0
  126. rasa/shared/providers/_configs/__init__.py +0 -0
  127. rasa/shared/providers/_configs/azure_openai_client_config.py +183 -0
  128. rasa/shared/providers/_configs/client_config.py +57 -0
  129. rasa/shared/providers/_configs/default_litellm_client_config.py +130 -0
  130. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +234 -0
  131. rasa/shared/providers/_configs/openai_client_config.py +175 -0
  132. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +176 -0
  133. rasa/shared/providers/_configs/utils.py +101 -0
  134. rasa/shared/providers/_ssl_verification_utils.py +124 -0
  135. rasa/shared/providers/embedding/__init__.py +0 -0
  136. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +259 -0
  137. rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
  138. rasa/shared/providers/embedding/azure_openai_embedding_client.py +277 -0
  139. rasa/shared/providers/embedding/default_litellm_embedding_client.py +102 -0
  140. rasa/shared/providers/embedding/embedding_client.py +90 -0
  141. rasa/shared/providers/embedding/embedding_response.py +41 -0
  142. rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
  143. rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
  144. rasa/shared/providers/llm/__init__.py +0 -0
  145. rasa/shared/providers/llm/_base_litellm_client.py +251 -0
  146. rasa/shared/providers/llm/azure_openai_llm_client.py +338 -0
  147. rasa/shared/providers/llm/default_litellm_llm_client.py +84 -0
  148. rasa/shared/providers/llm/llm_client.py +76 -0
  149. rasa/shared/providers/llm/llm_response.py +50 -0
  150. rasa/shared/providers/llm/openai_llm_client.py +155 -0
  151. rasa/shared/providers/llm/self_hosted_llm_client.py +293 -0
  152. rasa/shared/providers/mappings.py +75 -0
  153. rasa/shared/utils/cli.py +30 -0
  154. rasa/shared/utils/io.py +65 -2
  155. rasa/shared/utils/llm.py +246 -200
  156. rasa/shared/utils/yaml.py +121 -15
  157. rasa/studio/auth.py +6 -4
  158. rasa/studio/config.py +13 -4
  159. rasa/studio/constants.py +1 -0
  160. rasa/studio/data_handler.py +10 -3
  161. rasa/studio/download.py +19 -13
  162. rasa/studio/train.py +2 -3
  163. rasa/studio/upload.py +19 -11
  164. rasa/telemetry.py +113 -58
  165. rasa/tracing/instrumentation/attribute_extractors.py +32 -17
  166. rasa/utils/common.py +18 -19
  167. rasa/utils/endpoints.py +7 -4
  168. rasa/utils/json_utils.py +60 -0
  169. rasa/utils/licensing.py +9 -1
  170. rasa/utils/ml_utils.py +4 -2
  171. rasa/validator.py +213 -3
  172. rasa/version.py +1 -1
  173. rasa_pro-3.10.16.dist-info/METADATA +196 -0
  174. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/RECORD +179 -113
  175. rasa/nlu/classifiers/llm_intent_classifier.py +0 -519
  176. rasa/shared/providers/openai/clients.py +0 -43
  177. rasa/shared/providers/openai/session_handler.py +0 -110
  178. rasa_pro-3.9.18.dist-info/METADATA +0 -563
  179. /rasa/{shared/providers/openai → cli/project_templates/tutorial/actions}/__init__.py +0 -0
  180. /rasa/cli/project_templates/tutorial/{actions.py → actions/actions.py} +0 -0
  181. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/NOTICE +0 -0
  182. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/WHEEL +0 -0
  183. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any, Dict
5
+
6
+ from rasa.dialogue_understanding.stack.frames import PatternFlowStackFrame
7
+ from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
8
+
9
+ FLOW_PATTERN_RESTART = RASA_DEFAULT_FLOW_PATTERN_PREFIX + "restart"
10
+
11
+
12
+ @dataclass
13
+ class RestartPatternFlowStackFrame(PatternFlowStackFrame):
14
+ """A flow stack frame that can get added at the beginning of the conversation."""
15
+
16
+ flow_id: str = FLOW_PATTERN_RESTART
17
+ """The ID of the flow."""
18
+
19
+ @classmethod
20
+ def type(cls) -> str:
21
+ """Returns the type of the frame."""
22
+ return FLOW_PATTERN_RESTART
23
+
24
+ @staticmethod
25
+ def from_dict(data: Dict[str, Any]) -> RestartPatternFlowStackFrame:
26
+ """Creates a `DialogueStackFrame` from a dictionary.
27
+
28
+ Args:
29
+ data: The dictionary to create the `DialogueStackFrame` from.
30
+
31
+ Returns:
32
+ The created `DialogueStackFrame`.
33
+ """
34
+ return RestartPatternFlowStackFrame(
35
+ frame_id=data["frame_id"],
36
+ step_id=data["step_id"],
37
+ )
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from typing import Any, Dict
4
+
5
+ from rasa.dialogue_understanding.stack.frames import PatternFlowStackFrame
6
+ from rasa.shared.constants import RASA_DEFAULT_FLOW_PATTERN_PREFIX
7
+
8
+
9
+ FLOW_PATTERN_SESSION_START = RASA_DEFAULT_FLOW_PATTERN_PREFIX + "session_start"
10
+
11
+
12
+ @dataclass
13
+ class SessionStartPatternFlowStackFrame(PatternFlowStackFrame):
14
+ """A flow stack frame that can get added at the beginning of the conversation."""
15
+
16
+ flow_id: str = FLOW_PATTERN_SESSION_START
17
+ """The ID of the flow."""
18
+
19
+ @classmethod
20
+ def type(cls) -> str:
21
+ """Returns the type of the frame."""
22
+ return FLOW_PATTERN_SESSION_START
23
+
24
+ @staticmethod
25
+ def from_dict(data: Dict[str, Any]) -> SessionStartPatternFlowStackFrame:
26
+ """Creates a `DialogueStackFrame` from a dictionary.
27
+
28
+ Args:
29
+ data: The dictionary to create the `DialogueStackFrame` from.
30
+
31
+ Returns:
32
+ The created `DialogueStackFrame`.
33
+ """
34
+ return SessionStartPatternFlowStackFrame(
35
+ frame_id=data["frame_id"],
36
+ step_id=data["step_id"],
37
+ )
@@ -1,6 +1,7 @@
1
1
  from typing import List, Optional, Type, Set, Dict
2
2
 
3
3
  import structlog
4
+ from rasa.shared.core.training_data.structures import StoryGraph
4
5
  from rasa.dialogue_understanding.commands import (
5
6
  CancelFlowCommand,
6
7
  ClarifyCommand,
@@ -179,6 +180,7 @@ def execute_commands(
179
180
  tracker: DialogueStateTracker,
180
181
  all_flows: FlowsList,
181
182
  execution_context: ExecutionContext,
183
+ story_graph: Optional[StoryGraph] = None,
182
184
  ) -> List[Event]:
183
185
  """Executes a list of commands.
184
186
 
@@ -187,6 +189,7 @@ def execute_commands(
187
189
  tracker: The tracker to execute the commands on.
188
190
  all_flows: All flows.
189
191
  execution_context: Information about the single graph run.
192
+ story_graph: StoryGraph object with stories available for training.
190
193
 
191
194
  Returns:
192
195
  A list of the events that were created.
@@ -194,7 +197,9 @@ def execute_commands(
194
197
  commands: List[Command] = get_commands_from_tracker(tracker)
195
198
  original_tracker = tracker.copy()
196
199
 
197
- commands = clean_up_commands(commands, tracker, all_flows, execution_context)
200
+ commands = clean_up_commands(
201
+ commands, tracker, all_flows, execution_context, story_graph
202
+ )
198
203
 
199
204
  updated_flows = find_updated_flows(tracker, all_flows)
200
205
  if updated_flows:
@@ -326,6 +331,7 @@ def clean_up_commands(
326
331
  tracker: DialogueStateTracker,
327
332
  all_flows: FlowsList,
328
333
  execution_context: ExecutionContext,
334
+ story_graph: Optional[StoryGraph] = None,
329
335
  ) -> List[Command]:
330
336
  """Clean up a list of commands.
331
337
 
@@ -340,6 +346,7 @@ def clean_up_commands(
340
346
  tracker: The tracker to clean up the commands for.
341
347
  all_flows: All flows.
342
348
  execution_context: Information about a single graph run.
349
+ story_graph: StoryGraph object with stories available for training.
343
350
 
344
351
  Returns:
345
352
  The cleaned up commands.
@@ -386,7 +393,7 @@ def clean_up_commands(
386
393
  # handle chitchat command differently from other free-form answer commands
387
394
  elif isinstance(command, ChitChatAnswerCommand):
388
395
  clean_commands = clean_up_chitchat_command(
389
- clean_commands, command, all_flows, execution_context
396
+ clean_commands, command, all_flows, execution_context, story_graph
390
397
  )
391
398
 
392
399
  elif isinstance(command, FreeFormAnswerCommand):
@@ -563,6 +570,7 @@ def clean_up_chitchat_command(
563
570
  command: ChitChatAnswerCommand,
564
571
  flows: FlowsList,
565
572
  execution_context: ExecutionContext,
573
+ story_graph: Optional[StoryGraph] = None,
566
574
  ) -> List[Command]:
567
575
  """Clean up a chitchat answer command.
568
576
 
@@ -574,6 +582,7 @@ def clean_up_chitchat_command(
574
582
  command: The command to clean up.
575
583
  flows: All flows.
576
584
  execution_context: Information about a single graph run.
585
+ story_graph: StoryGraph object with stories available for training.
577
586
  Returns:
578
587
  The cleaned up commands.
579
588
  """
@@ -599,7 +608,11 @@ def clean_up_chitchat_command(
599
608
  )
600
609
  defines_intentless_policy = execution_context.has_node(IntentlessPolicy)
601
610
 
602
- if has_action_trigger_chitchat and not defines_intentless_policy:
611
+ has_e2e_stories = True if (story_graph and story_graph.has_e2e_stories()) else False
612
+
613
+ if (has_action_trigger_chitchat and not defines_intentless_policy) or (
614
+ defines_intentless_policy and not has_e2e_stories
615
+ ):
603
616
  resulting_commands.insert(
604
617
  0, CannotHandleCommand(RASA_PATTERN_CANNOT_HANDLE_CHITCHAT)
605
618
  )
@@ -9,6 +9,7 @@ from rasa.engine.storage.storage import ModelStorage
9
9
  from rasa.shared.core.events import Event
10
10
  from rasa.shared.core.flows import FlowsList
11
11
  from rasa.shared.core.trackers import DialogueStateTracker
12
+ from rasa.shared.core.training_data.structures import StoryGraph
12
13
 
13
14
 
14
15
  class CommandProcessorComponent(GraphComponent):
@@ -31,9 +32,12 @@ class CommandProcessorComponent(GraphComponent):
31
32
  return cls(execution_context)
32
33
 
33
34
  def execute_commands(
34
- self, tracker: DialogueStateTracker, flows: FlowsList
35
+ self,
36
+ tracker: DialogueStateTracker,
37
+ flows: FlowsList,
38
+ story_graph: StoryGraph,
35
39
  ) -> List[Event]:
36
40
  """Execute commands to update tracker state."""
37
41
  return rasa.dialogue_understanding.processor.command_processor.execute_commands(
38
- tracker, flows, self._execution_context
42
+ tracker, flows, self._execution_context, story_graph
39
43
  )
@@ -0,0 +1,134 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Optional, Set, TYPE_CHECKING
3
+
4
+ import structlog
5
+
6
+ from rasa.e2e_test.assertions import _get_all_assertion_subclasses
7
+
8
+ if TYPE_CHECKING:
9
+ from rasa.e2e_test.assertions import Assertion
10
+ from rasa.e2e_test.e2e_test_case import TestCase
11
+ from rasa.e2e_test.e2e_test_result import TestResult
12
+
13
+ structlogger = structlog.get_logger()
14
+
15
+
16
+ @dataclass
17
+ class AccuracyCalculation:
18
+ """Data class for storing the accuracy calculation for an assertion type."""
19
+
20
+ assertion_type: str
21
+ accuracy: float
22
+
23
+
24
+ class AggregateTestStatsCalculator:
25
+ """Class for calculating the aggregate test statistics for assertion types."""
26
+
27
+ def __init__(
28
+ self,
29
+ passed_results: List["TestResult"],
30
+ failed_results: List["TestResult"],
31
+ test_cases: List["TestCase"],
32
+ ) -> None:
33
+ self.passed_results = passed_results
34
+ self.failed_results = failed_results
35
+ self.test_cases = test_cases
36
+
37
+ self.failed_assertion_set: Set["Assertion"] = set()
38
+ self.failed_test_cases_without_assertion_failure: Set[str] = set()
39
+ self.passed_count_mapping = {
40
+ subclass_type: 0
41
+ for subclass_type in _get_all_assertion_subclasses().keys()
42
+ if subclass_type != ""
43
+ }
44
+ self.failed_count_mapping = {
45
+ subclass_type: 0
46
+ for subclass_type in _get_all_assertion_subclasses().keys()
47
+ if subclass_type != ""
48
+ }
49
+
50
+ def calculate(self) -> List[AccuracyCalculation]:
51
+ """Calculates the aggregate test statistics for assertion types."""
52
+ self._update_failed_count_mapping()
53
+ self._update_passed_count_mapping()
54
+
55
+ accuracy_calculations = []
56
+
57
+ for assertion_type in self.passed_count_mapping.keys():
58
+ accuracy = self._calculate_accuracy(assertion_type)
59
+ if accuracy is None:
60
+ continue
61
+
62
+ accuracy_calculations.append(AccuracyCalculation(assertion_type, accuracy))
63
+
64
+ return accuracy_calculations
65
+
66
+ def _calculate_accuracy(self, assertion_type: str) -> Optional[float]:
67
+ """Calculates the accuracy for the given assertion type."""
68
+ passed_count = self.passed_count_mapping[assertion_type]
69
+ failed_count = self.failed_count_mapping[assertion_type]
70
+
71
+ total_count = passed_count + failed_count
72
+
73
+ if total_count == 0:
74
+ structlogger.debug(
75
+ "aggregate_test_stats.calculate_accuracy."
76
+ "no_test_cases_for_assertion_type",
77
+ assertion_type=assertion_type,
78
+ )
79
+ return None
80
+
81
+ return passed_count / total_count
82
+
83
+ def _update_passed_count_mapping(self) -> None:
84
+ """Updates the passed count mapping based on the passed results.
85
+
86
+ We only count the assertions of passed tests and those
87
+ that are not in the failed assertion set.
88
+ We also do not count the assertions that follow a failed assertion.
89
+ """
90
+ passed_test_case_names = [
91
+ passed.test_case.name for passed in self.passed_results
92
+ ]
93
+ # We filter out test cases that failed without an assertion failure
94
+ filtered_test_cases = [
95
+ test_case
96
+ for test_case in self.test_cases
97
+ if test_case.name not in self.failed_test_cases_without_assertion_failure
98
+ ]
99
+
100
+ for test_case in filtered_test_cases:
101
+ if test_case.name in passed_test_case_names:
102
+ for step in test_case.steps:
103
+ if step.assertions is None:
104
+ continue
105
+
106
+ for assertion in step.assertions:
107
+ self.passed_count_mapping[assertion.type()] += 1
108
+ else:
109
+ for step in test_case.steps:
110
+ if step.assertions is None:
111
+ continue
112
+
113
+ for assertion in step.assertions:
114
+ if assertion not in self.failed_assertion_set:
115
+ self.passed_count_mapping[assertion.type()] += 1
116
+ else:
117
+ break
118
+
119
+ def _update_failed_count_mapping(self) -> None:
120
+ """Updates the failed count mapping based on the failed results."""
121
+ for failed in self.failed_results:
122
+ if failed.assertion_failure is None:
123
+ structlogger.debug(
124
+ "aggregate_test_stats.calculate."
125
+ "no_assertion_failure_in_failed_result",
126
+ test_case=failed.test_case.name,
127
+ )
128
+ self.failed_test_cases_without_assertion_failure.add(
129
+ failed.test_case.name
130
+ )
131
+ continue
132
+
133
+ self.failed_assertion_set.add(failed.assertion_failure.assertion)
134
+ self.failed_count_mapping[failed.assertion_failure.assertion.type()] += 1