An case-ignoring enum matching choices by unique prefixes/substrings.
| 3308 | |
| 3309 | |
| 3310 | class FuzzyEnum(Enum[G]): |
| 3311 | """An case-ignoring enum matching choices by unique prefixes/substrings.""" |
| 3312 | |
| 3313 | case_sensitive = False |
| 3314 | #: If True, choices match anywhere in the string, otherwise match prefixes. |
| 3315 | substring_matching = False |
| 3316 | |
| 3317 | def __init__( |
| 3318 | self: FuzzyEnum[t.Any], |
| 3319 | values: t.Any, |
| 3320 | default_value: t.Any = Undefined, |
| 3321 | case_sensitive: bool = False, |
| 3322 | substring_matching: bool = False, |
| 3323 | **kwargs: t.Any, |
| 3324 | ) -> None: |
| 3325 | self.case_sensitive = case_sensitive |
| 3326 | self.substring_matching = substring_matching |
| 3327 | super().__init__(values, default_value=default_value, **kwargs) |
| 3328 | |
| 3329 | def validate(self, obj: t.Any, value: t.Any) -> G: |
| 3330 | if not isinstance(value, str): |
| 3331 | self.error(obj, value) |
| 3332 | |
| 3333 | conv_func = (lambda c: c) if self.case_sensitive else lambda c: c.lower() |
| 3334 | substring_matching = self.substring_matching |
| 3335 | match_func = (lambda v, c: v in c) if substring_matching else (lambda v, c: c.startswith(v)) |
| 3336 | value = conv_func(value) # type:ignore[no-untyped-call] |
| 3337 | choices = self.values or [] |
| 3338 | matches = [match_func(value, conv_func(c)) for c in choices] # type:ignore[no-untyped-call] |
| 3339 | if sum(matches) == 1: |
| 3340 | for v, m in zip(choices, matches): |
| 3341 | if m: |
| 3342 | return v |
| 3343 | |
| 3344 | self.error(obj, value) |
| 3345 | |
| 3346 | def _info(self, as_rst: bool = False) -> str: |
| 3347 | """Returns a description of the trait.""" |
| 3348 | none = " or %s" % ("`None`" if as_rst else "None") if self.allow_none else "" |
| 3349 | case = "sensitive" if self.case_sensitive else "insensitive" |
| 3350 | substr = "substring" if self.substring_matching else "prefix" |
| 3351 | return f"any case-{case} {substr} of {self._choices_str(as_rst)}{none}" |
| 3352 | |
| 3353 | def info(self) -> str: |
| 3354 | return self._info(as_rst=False) |
| 3355 | |
| 3356 | def info_rst(self) -> str: |
| 3357 | return self._info(as_rst=True) |
| 3358 | |
| 3359 | |
| 3360 | class Container(Instance[T]): |
no outgoing calls
no test coverage detected
searching dependent graphs…