Coverage for langsmith/_internal/_edit_distance.py: 0%
26 statements
« prev ^ index » next coverage.py v7.10.1, created at 2025-12-11 16:15 -0800
« prev ^ index » next coverage.py v7.10.1, created at 2025-12-11 16:15 -0800
1from typing import Any, Callable, Literal, Optional
3from typing_extensions import TypedDict
5METRICS = Literal[
6 "damerau_levenshtein",
7 "levenshtein",
8 "jaro",
9 "jaro_winkler",
10 "hamming",
11 "indel",
12]
15class EditDistanceConfig(TypedDict, total=False):
16 metric: METRICS
17 normalize_score: bool
20class EditDistance:
21 def __init__(
22 self,
23 config: Optional[EditDistanceConfig] = None,
24 ):
25 config = config or {}
26 metric = config.get("metric") or "damerau_levenshtein"
27 self.metric = self._get_metric(
28 metric, normalize_score=config.get("normalize_score", True)
29 )
31 def evaluate(
32 self,
33 prediction: str,
34 reference: Optional[str] = None,
35 ) -> float:
36 return self.metric(prediction, reference)
38 @staticmethod
39 def _get_metric(distance: str, normalize_score: bool = True) -> Callable:
40 try:
41 from rapidfuzz import ( # type: ignore[import-not-found]
42 distance as rf_distance,
43 )
44 except ImportError:
45 raise ImportError(
46 "This operation requires the rapidfuzz library to use."
47 "Please install it with `pip install -U rapidfuzz`."
48 )
50 module_map: dict[str, Any] = {
51 "damerau_levenshtein": rf_distance.DamerauLevenshtein,
52 "levenshtein": rf_distance.Levenshtein,
53 "jaro": rf_distance.Jaro,
54 "jaro_winkler": rf_distance.JaroWinkler,
55 "hamming": rf_distance.Hamming,
56 "indel": rf_distance.Indel,
57 }
58 if distance not in module_map:
59 raise ValueError(
60 f"Invalid distance metric: {distance}"
61 f"\nMust be one of: {list(module_map)}"
62 )
63 module = module_map[distance]
64 if normalize_score:
65 return module.normalized_distance
66 else:
67 return module.distance