Files
wehub-resource-sync dc6079821b
CI Github Actions / Run Tests (push) Waiting to run
Automatic PR Merger / mergepal (push) Waiting to run
Semgrep / Semgrep Workflow Security Scan (push) Waiting to run
Docs Tests / Check for file changes (push) Has been cancelled
Docs Tests / Test Documentation (push) Has been cancelled
Docs Tests / Documentation Linting Checks (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Has been cancelled
Continuous Integration / Check for file changes (push) Has been cancelled
Continuous Integration / Wait for docs tests (push) Has been cancelled
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Check for changelog (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Upload coverage reports to codeclimate (push) Has been cancelled
Continuous Integration / Run Non-Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Run Broker Integration Tests (push) Has been cancelled
Continuous Integration / Run Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Build Docker base images and setup environment (push) Has been cancelled
Continuous Integration / Build Docker (default) (push) Has been cancelled
Continuous Integration / Build Docker (full) (push) Has been cancelled
Continuous Integration / Build Docker (mitie-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-de) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-it) (push) Has been cancelled
Continuous Integration / Deploy to PyPI (push) Has been cancelled
Continuous Integration / Notify Slack & Publish Release Notes (push) Has been cancelled
Publish Documentation / Evaluate release tag (push) Has been cancelled
Publish Documentation / Prebuild Docs (push) Has been cancelled
Publish Documentation / Preview Docs (push) Has been cancelled
Publish Documentation / Check for file changes (push) Has been cancelled
Publish Documentation / Publish Docs (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:47 +08:00

292 lines
10 KiB
Python

import logging
import os
from typing import Text, Dict, List, Optional, Any
from packaging import version
from packaging.version import LegacyVersion
from pykwalify.errors import SchemaError
from ruamel.yaml.constructor import DuplicateKeyError
import rasa.shared
from rasa.shared.exceptions import (
YamlException,
YamlSyntaxException,
SchemaValidationError,
)
import rasa.shared.utils.io
from rasa.shared.constants import (
DOCS_URL_TRAINING_DATA,
PACKAGE_NAME,
LATEST_TRAINING_DATA_FORMAT_VERSION,
SCHEMA_EXTENSIONS_FILE,
RESPONSES_SCHEMA_FILE,
)
logger = logging.getLogger(__name__)
KEY_TRAINING_DATA_FORMAT_VERSION = "version"
class YamlValidationException(YamlException, ValueError):
"""Raised if a yaml file does not correspond to the expected schema."""
def __init__(
self,
message: Text,
validation_errors: Optional[List[SchemaError.SchemaErrorEntry]] = None,
filename: Optional[Text] = None,
content: Any = None,
) -> None:
"""Create The Error.
Args:
message: error message
validation_errors: validation errors
filename: name of the file which was validated
content: yaml content loaded from the file (used for line information)
"""
super(YamlValidationException, self).__init__(filename)
self.message = message
self.validation_errors = validation_errors
self.content = content
def __str__(self) -> Text:
msg = ""
if self.filename:
msg += f"Failed to validate '{self.filename}'. "
else:
msg += "Failed to validate YAML. "
msg += self.message
if self.validation_errors:
unique_errors = {}
for error in self.validation_errors:
line_number = self._line_number_for_path(self.content, error.path)
if line_number and self.filename:
error_representation = f" in {self.filename}:{line_number}:\n"
elif line_number:
error_representation = f" in Line {line_number}:\n"
else:
error_representation = ""
error_representation += f" {error}"
unique_errors[str(error)] = error_representation
error_msg = "\n".join(unique_errors.values())
msg += f":\n{error_msg}"
return msg
def _line_number_for_path(self, current: Any, path: Text) -> Optional[int]:
"""Get line number for a yaml path in the current content.
Implemented using recursion: algorithm goes down the path navigating to the
leaf in the YAML tree. Unfortunately, not all nodes returned from the
ruamel yaml parser have line numbers attached (arrays have them, dicts have
them), e.g. strings don't have attached line numbers.
If we arrive at a node that has no line number attached, we'll return the
line number of the parent - that is as close as it gets.
Args:
current: current content
path: path to traverse within the content
Returns:
the line number of the path in the content.
"""
if not current:
return None
this_line = current.lc.line + 1 if hasattr(current, "lc") else None
if not path:
return this_line
if "/" in path:
head, tail = path.split("/", 1)
else:
head, tail = path, ""
if head:
if isinstance(current, dict) and head in current:
return self._line_number_for_path(current[head], tail) or this_line
elif isinstance(current, list) and head.isdigit():
return self._line_number_for_path(current[int(head)], tail) or this_line
else:
return this_line
return self._line_number_for_path(current, tail) or this_line
def validate_yaml_schema(
yaml_file_content: Text, schema_path: Text, package_name: Text = PACKAGE_NAME
) -> None:
"""Validate yaml content.
Args:
yaml_file_content: the content of the yaml file to be validated
schema_path: the schema of the yaml file
package_name: the name of the package the schema is located in. defaults
to `rasa`.
"""
from pykwalify.core import Core
from pykwalify.errors import SchemaError
from ruamel.yaml import YAMLError
import pkg_resources
import logging
log = logging.getLogger("pykwalify")
log.setLevel(logging.CRITICAL)
try:
# we need "rt" since
# it will add meta information to the parsed output. this meta information
# will include e.g. at which line an object was parsed. this is very
# helpful when we validate files later on and want to point the user to the
# right line
source_data = rasa.shared.utils.io.read_yaml(
yaml_file_content, reader_type=["safe", "rt"]
)
except (YAMLError, DuplicateKeyError) as e:
raise YamlSyntaxException(underlying_yaml_exception=e)
schema_file = pkg_resources.resource_filename(package_name, schema_path)
schema_utils_file = pkg_resources.resource_filename(
PACKAGE_NAME, RESPONSES_SCHEMA_FILE
)
schema_extensions = pkg_resources.resource_filename(
PACKAGE_NAME, SCHEMA_EXTENSIONS_FILE
)
# Load schema content using our YAML loader as `pykwalify` uses a global instance
# which can fail when used concurrently
schema_content = rasa.shared.utils.io.read_yaml_file(schema_file)
schema_utils_content = rasa.shared.utils.io.read_yaml_file(schema_utils_file)
schema_content = dict(schema_content, **schema_utils_content)
c = Core(
source_data=source_data,
schema_data=schema_content,
extensions=[schema_extensions],
)
try:
c.validate(raise_exception=True)
except SchemaError:
raise YamlValidationException(
"Please make sure the file is correct and all "
"mandatory parameters are specified. Here are the errors "
"found during validation",
c.errors,
content=source_data,
)
def validate_training_data(json_data: Dict[Text, Any], schema: Dict[Text, Any]) -> None:
"""Validate rasa training data format to ensure proper training.
Args:
json_data: the data to validate
schema: the schema
Raises:
SchemaValidationError if validation fails.
"""
from jsonschema import validate
from jsonschema import ValidationError
try:
validate(json_data, schema)
except ValidationError as e:
e.message += (
f". Failed to validate data, make sure your data "
f"is valid. For more information about the format visit "
f"{DOCS_URL_TRAINING_DATA}."
)
raise SchemaValidationError.create_from(e) from e
def validate_training_data_format_version(
yaml_file_content: Dict[Text, Any], filename: Optional[Text]
) -> bool:
"""Validates version on the training data content using `version` field
and warns users if the file is not compatible with the current version of
Rasa Open Source.
Args:
yaml_file_content: Raw content of training data file as a dictionary.
filename: Name of the validated file.
Returns:
`True` if the file can be processed by current version of Rasa Open Source,
`False` otherwise.
"""
if filename:
filename = os.path.abspath(filename)
if not isinstance(yaml_file_content, dict):
raise YamlValidationException(
"YAML content in is not a mapping, can not validate training "
"data schema version.",
filename=filename,
)
version_value = yaml_file_content.get(KEY_TRAINING_DATA_FORMAT_VERSION)
if not version_value:
# not raising here since it's not critical
logger.info(
f"The '{KEY_TRAINING_DATA_FORMAT_VERSION}' key is missing in "
f"the training data file {filename}. "
f"Rasa Open Source will read the file as a "
f"version '{LATEST_TRAINING_DATA_FORMAT_VERSION}' file. "
f"See {DOCS_URL_TRAINING_DATA}."
)
return True
try:
if isinstance(version_value, str):
version_value = version_value.strip("\"'")
parsed_version = version.parse(version_value)
latest_version = version.parse(LATEST_TRAINING_DATA_FORMAT_VERSION)
if isinstance(parsed_version, LegacyVersion):
raise TypeError
if parsed_version < latest_version:
rasa.shared.utils.io.raise_warning(
f"Training data file {filename} has a lower "
f"format version than your Rasa Open Source installation: "
f"{version_value} < {LATEST_TRAINING_DATA_FORMAT_VERSION}. "
f"Rasa Open Source will read the file as a version "
f"{LATEST_TRAINING_DATA_FORMAT_VERSION} file. "
f"Please update your version key to "
f"{LATEST_TRAINING_DATA_FORMAT_VERSION}. "
f"See {DOCS_URL_TRAINING_DATA}."
)
if latest_version >= parsed_version:
return True
except TypeError:
rasa.shared.utils.io.raise_warning(
f"Training data file {filename} must specify "
f"'{KEY_TRAINING_DATA_FORMAT_VERSION}' as string, for example:\n"
f"{KEY_TRAINING_DATA_FORMAT_VERSION}: "
f"'{LATEST_TRAINING_DATA_FORMAT_VERSION}'\n"
f"Rasa Open Source will read the file as a "
f"version '{LATEST_TRAINING_DATA_FORMAT_VERSION}' file.",
docs=DOCS_URL_TRAINING_DATA,
)
return True
rasa.shared.utils.io.raise_warning(
f"Training data file {filename} has a greater "
f"format version than your Rasa Open Source installation: "
f"{version_value} > {LATEST_TRAINING_DATA_FORMAT_VERSION}. "
f"Please consider updating to the latest version of Rasa Open Source."
f"This file will be skipped.",
docs=DOCS_URL_TRAINING_DATA,
)
return False