diff --git a/.changes/unreleased/Fixes-20230914-134708.yaml b/.changes/unreleased/Fixes-20230914-134708.yaml new file mode 100644 index 00000000..b025e4bb --- /dev/null +++ b/.changes/unreleased/Fixes-20230914-134708.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Disallow dunders semantic object names +time: 2023-09-14T13:47:08.907492-07:00 +custom: + Author: QMalcolm + Issue: "149" diff --git a/dbt_semantic_interfaces/validations/unique_valid_name.py b/dbt_semantic_interfaces/validations/unique_valid_name.py index 7692ebf2..e744c705 100644 --- a/dbt_semantic_interfaces/validations/unique_valid_name.py +++ b/dbt_semantic_interfaces/validations/unique_valid_name.py @@ -59,7 +59,11 @@ class UniqueAndValidNameRule(SemanticManifestValidationRule[SemanticManifestT], * Names of semantic models, dimension sets and metric sets in the model are unique / valid. """ - NAME_REGEX = re.compile(r"\A[a-z][a-z0-9_]*[a-z0-9]\Z") + # name must start with a lower case letter + # name must end with a number or lower case letter + # name may include lower case letters, numbers, and underscores + # name may not contain dunders (two sequential underscores + NAME_REGEX = re.compile(r"\A[a-z]((?!__)[a-z0-9_])*[a-z0-9]\Z") @staticmethod def check_valid_name(name: str, context: Optional[ValidationContext] = None) -> List[ValidationIssue]: # noqa: D @@ -69,9 +73,10 @@ def check_valid_name(name: str, context: Optional[ValidationContext] = None) -> issues.append( ValidationError( context=context, - message=f"Invalid name `{name}` - names should only consist of lower case letters, numbers, " - f"and underscores. In addition, names should start with a lower case letter, and should not end " - f"with an underscore, and they must be at least 2 characters long.", + message=f"Invalid name `{name}` - names may only contain lower case letters, numbers, " + f"and underscores. Additionally, names must start with a lower case letter, cannot end " + f"with an underscore, cannot contain dunders (double underscores, or __), and must be " + f"at least 2 characters long.", ) ) if name.upper() in TimeGranularity.list_names(): diff --git a/tests/validations/test_unique_valid_name.py b/tests/validations/test_unique_valid_name.py index 3034bf00..f0906f36 100644 --- a/tests/validations/test_unique_valid_name.py +++ b/tests/validations/test_unique_valid_name.py @@ -206,6 +206,7 @@ def test_invalid_names() -> None: # noqa:D assert UniqueAndValidNameRule.check_valid_name("_no_leading_underscore") != [] assert UniqueAndValidNameRule.check_valid_name("no_trailing_underscore_") != [] assert UniqueAndValidNameRule.check_valid_name("_definitely_no_leading_and_trailing_underscore_") != [] + assert UniqueAndValidNameRule.check_valid_name("name__with__dunders") != [] # time granularity values are reserved assert UniqueAndValidNameRule.check_valid_name("day") != []