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.
- README.md +0 -374
- rasa/__init__.py +1 -2
- rasa/__main__.py +5 -0
- rasa/anonymization/anonymization_rule_executor.py +2 -2
- rasa/api.py +27 -23
- rasa/cli/arguments/data.py +27 -2
- rasa/cli/arguments/default_arguments.py +25 -3
- rasa/cli/arguments/run.py +9 -9
- rasa/cli/arguments/train.py +11 -3
- rasa/cli/data.py +70 -8
- rasa/cli/e2e_test.py +104 -431
- rasa/cli/evaluate.py +1 -1
- rasa/cli/interactive.py +1 -0
- rasa/cli/llm_fine_tuning.py +398 -0
- rasa/cli/project_templates/calm/endpoints.yml +1 -1
- rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
- rasa/cli/run.py +15 -14
- rasa/cli/scaffold.py +10 -8
- rasa/cli/studio/studio.py +35 -5
- rasa/cli/train.py +56 -8
- rasa/cli/utils.py +22 -5
- rasa/cli/x.py +1 -1
- rasa/constants.py +7 -1
- rasa/core/actions/action.py +98 -49
- rasa/core/actions/action_run_slot_rejections.py +4 -1
- rasa/core/actions/custom_action_executor.py +9 -6
- rasa/core/actions/direct_custom_actions_executor.py +80 -0
- rasa/core/actions/e2e_stub_custom_action_executor.py +68 -0
- rasa/core/actions/grpc_custom_action_executor.py +2 -2
- rasa/core/actions/http_custom_action_executor.py +6 -5
- rasa/core/agent.py +21 -17
- rasa/core/channels/__init__.py +2 -0
- rasa/core/channels/audiocodes.py +1 -16
- rasa/core/channels/voice_aware/__init__.py +0 -0
- rasa/core/channels/voice_aware/jambonz.py +103 -0
- rasa/core/channels/voice_aware/jambonz_protocol.py +344 -0
- rasa/core/channels/voice_aware/utils.py +20 -0
- rasa/core/channels/voice_native/__init__.py +0 -0
- rasa/core/constants.py +6 -1
- rasa/core/information_retrieval/faiss.py +7 -4
- rasa/core/information_retrieval/information_retrieval.py +8 -0
- rasa/core/information_retrieval/milvus.py +9 -2
- rasa/core/information_retrieval/qdrant.py +1 -1
- rasa/core/nlg/contextual_response_rephraser.py +32 -10
- rasa/core/nlg/summarize.py +4 -3
- rasa/core/policies/enterprise_search_policy.py +113 -45
- rasa/core/policies/flows/flow_executor.py +122 -76
- rasa/core/policies/intentless_policy.py +83 -29
- rasa/core/processor.py +72 -54
- rasa/core/run.py +5 -4
- rasa/core/tracker_store.py +8 -4
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +56 -57
- rasa/dialogue_understanding/coexistence/llm_based_router.py +53 -13
- rasa/dialogue_understanding/commands/__init__.py +6 -0
- rasa/dialogue_understanding/commands/restart_command.py +58 -0
- rasa/dialogue_understanding/commands/session_start_command.py +59 -0
- rasa/dialogue_understanding/commands/utils.py +40 -0
- rasa/dialogue_understanding/generator/constants.py +10 -3
- rasa/dialogue_understanding/generator/flow_retrieval.py +21 -5
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +13 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +134 -90
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +47 -7
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +127 -41
- rasa/dialogue_understanding/patterns/restart.py +37 -0
- rasa/dialogue_understanding/patterns/session_start.py +37 -0
- rasa/dialogue_understanding/processor/command_processor.py +16 -3
- rasa/dialogue_understanding/processor/command_processor_component.py +6 -2
- rasa/e2e_test/aggregate_test_stats_calculator.py +134 -0
- rasa/e2e_test/assertions.py +1223 -0
- rasa/e2e_test/assertions_schema.yml +106 -0
- rasa/e2e_test/constants.py +20 -0
- rasa/e2e_test/e2e_config.py +220 -0
- rasa/e2e_test/e2e_config_schema.yml +26 -0
- rasa/e2e_test/e2e_test_case.py +131 -8
- rasa/e2e_test/e2e_test_converter.py +363 -0
- rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
- rasa/e2e_test/e2e_test_coverage_report.py +364 -0
- rasa/e2e_test/e2e_test_result.py +26 -6
- rasa/e2e_test/e2e_test_runner.py +493 -71
- rasa/e2e_test/e2e_test_schema.yml +96 -0
- rasa/e2e_test/pykwalify_extensions.py +39 -0
- rasa/e2e_test/stub_custom_action.py +70 -0
- rasa/e2e_test/utils/__init__.py +0 -0
- rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
- rasa/e2e_test/utils/io.py +598 -0
- rasa/e2e_test/utils/validation.py +80 -0
- rasa/engine/graph.py +9 -3
- rasa/engine/recipes/default_components.py +0 -2
- rasa/engine/recipes/default_recipe.py +10 -2
- rasa/engine/storage/local_model_storage.py +40 -12
- rasa/engine/validation.py +78 -1
- rasa/env.py +9 -0
- rasa/graph_components/providers/story_graph_provider.py +59 -6
- rasa/llm_fine_tuning/__init__.py +0 -0
- rasa/llm_fine_tuning/annotation_module.py +241 -0
- rasa/llm_fine_tuning/conversations.py +144 -0
- rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
- rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
- rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
- rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
- rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
- rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
- rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
- rasa/llm_fine_tuning/storage.py +174 -0
- rasa/llm_fine_tuning/train_test_split_module.py +441 -0
- rasa/model_training.py +56 -16
- rasa/nlu/persistor.py +157 -36
- rasa/server.py +45 -10
- rasa/shared/constants.py +76 -16
- rasa/shared/core/domain.py +27 -19
- rasa/shared/core/events.py +28 -2
- rasa/shared/core/flows/flow.py +208 -13
- rasa/shared/core/flows/flow_path.py +84 -0
- rasa/shared/core/flows/flows_list.py +33 -11
- rasa/shared/core/flows/flows_yaml_schema.json +269 -193
- rasa/shared/core/flows/validation.py +112 -25
- rasa/shared/core/flows/yaml_flows_io.py +149 -10
- rasa/shared/core/trackers.py +6 -0
- rasa/shared/core/training_data/structures.py +20 -0
- rasa/shared/core/training_data/visualization.html +2 -2
- rasa/shared/exceptions.py +4 -0
- rasa/shared/importers/importer.py +64 -16
- rasa/shared/nlu/constants.py +2 -0
- rasa/shared/providers/_configs/__init__.py +0 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +183 -0
- rasa/shared/providers/_configs/client_config.py +57 -0
- rasa/shared/providers/_configs/default_litellm_client_config.py +130 -0
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +234 -0
- rasa/shared/providers/_configs/openai_client_config.py +175 -0
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +176 -0
- rasa/shared/providers/_configs/utils.py +101 -0
- rasa/shared/providers/_ssl_verification_utils.py +124 -0
- rasa/shared/providers/embedding/__init__.py +0 -0
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +259 -0
- rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +277 -0
- rasa/shared/providers/embedding/default_litellm_embedding_client.py +102 -0
- rasa/shared/providers/embedding/embedding_client.py +90 -0
- rasa/shared/providers/embedding/embedding_response.py +41 -0
- rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
- rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
- rasa/shared/providers/llm/__init__.py +0 -0
- rasa/shared/providers/llm/_base_litellm_client.py +251 -0
- rasa/shared/providers/llm/azure_openai_llm_client.py +338 -0
- rasa/shared/providers/llm/default_litellm_llm_client.py +84 -0
- rasa/shared/providers/llm/llm_client.py +76 -0
- rasa/shared/providers/llm/llm_response.py +50 -0
- rasa/shared/providers/llm/openai_llm_client.py +155 -0
- rasa/shared/providers/llm/self_hosted_llm_client.py +293 -0
- rasa/shared/providers/mappings.py +75 -0
- rasa/shared/utils/cli.py +30 -0
- rasa/shared/utils/io.py +65 -2
- rasa/shared/utils/llm.py +246 -200
- rasa/shared/utils/yaml.py +121 -15
- rasa/studio/auth.py +6 -4
- rasa/studio/config.py +13 -4
- rasa/studio/constants.py +1 -0
- rasa/studio/data_handler.py +10 -3
- rasa/studio/download.py +19 -13
- rasa/studio/train.py +2 -3
- rasa/studio/upload.py +19 -11
- rasa/telemetry.py +113 -58
- rasa/tracing/instrumentation/attribute_extractors.py +32 -17
- rasa/utils/common.py +18 -19
- rasa/utils/endpoints.py +7 -4
- rasa/utils/json_utils.py +60 -0
- rasa/utils/licensing.py +9 -1
- rasa/utils/ml_utils.py +4 -2
- rasa/validator.py +213 -3
- rasa/version.py +1 -1
- rasa_pro-3.10.16.dist-info/METADATA +196 -0
- {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/RECORD +179 -113
- rasa/nlu/classifiers/llm_intent_classifier.py +0 -519
- rasa/shared/providers/openai/clients.py +0 -43
- rasa/shared/providers/openai/session_handler.py +0 -110
- rasa_pro-3.9.18.dist-info/METADATA +0 -563
- /rasa/{shared/providers/openai → cli/project_templates/tutorial/actions}/__init__.py +0 -0
- /rasa/cli/project_templates/tutorial/{actions.py → actions/actions.py} +0 -0
- {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/NOTICE +0 -0
- {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/WHEEL +0 -0
- {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(
|
|
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
|
|
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,
|
|
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
|