1- import re
21from functools import cache
32from typing import ClassVar , Final
43
54from typing_extensions import dataclass_transform
65
7- from great_expectations .compatibility .pydantic import BaseModel , ModelMetaclass
6+ from great_expectations .compatibility .pydantic import BaseModel , ModelMetaclass , StrictStr
87from great_expectations .metrics .domain import AbstractClassInstantiationError , Domain
98from great_expectations .validator .metric_configuration import (
109 MetricConfiguration ,
@@ -61,7 +60,7 @@ class Metric(BaseModel, metaclass=MetaMetric):
6160 MetricConfiguration: Configuration class for metric computation
6261 """
6362
64- name : ClassVar [str ]
63+ name : ClassVar [StrictStr ]
6564
6665 class Config :
6766 arbitrary_types_allowed = True
@@ -70,7 +69,6 @@ class Config:
7069 def __new__ (cls , * args , ** kwargs ):
7170 if cls is Metric :
7271 raise AbstractClassInstantiationError (cls .__name__ )
73- cls .name = cls ._get_metric_name ()
7472 return super ().__new__ (cls )
7573
7674 @property
@@ -84,41 +82,6 @@ def config(self) -> MetricConfiguration:
8482 metric_value_set = frozenset (self .dict ().items ()),
8583 )
8684
87- @staticmethod
88- def _pascal_to_snake (class_name : str ) -> str :
89- # Adds an underscore between a sequence of uppercase letters and an uppercase-lowercase pair
90- # APIFunctionMetric -> API_FunctionMetric
91- class_name = re .sub (r"([A-Z]+)([A-Z][a-z])" , r"\1_\2" , class_name )
92- # Adds an underscore between a lowercase letter/digit and an uppercase letter
93- # APIFunctionMetric -> API_Function_Metric
94- class_name = re .sub (r"([a-z\d])([A-Z])" , r"\1_\2" , class_name )
95- # Convert the entire string to lowercase
96- # API_Function_Metric -> api_function_metric
97- return class_name .lower ()
98-
99- @classmethod
100- def _get_metric_name (cls ) -> str :
101- """The name of the metric as it exists in the registry."""
102- for base_type in cls .__bases__ :
103- if issubclass (base_type , Domain ):
104- domain_class_name = str (base_type .__name__ )
105- metric_class_name = str (cls .__name__ )
106- domain_class_snake_case = Metric ._pascal_to_snake (domain_class_name )
107- translated_domain_name = domain_class_snake_case .replace ("batch" , "table" )
108- metric_class_snake_case = Metric ._pascal_to_snake (metric_class_name )
109- # the convention is that the metric class name includes the domain class name
110- # but the metric names don't repeat the domain name, so we remove it
111- return "." .join (
112- [
113- translated_domain_name ,
114- metric_class_snake_case .replace (domain_class_snake_case , "" ).strip ("_" ),
115- ]
116- )
117-
118- # this should never be reached
119- # that a Domain exists in __bases__ should have been confirmed in MetaMetric.__new__
120- raise MixinTypeError (cls .__name__ , "Domain" )
121-
12285 @staticmethod
12386 @cache
12487 def _to_config (
0 commit comments