validators.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. # -*- coding: utf-8 -*-
  2. """
  3. Validator-Klassen für verschiedene Validierungsszenarien.
  4. Bietet eine erweiterbare Hierarchie von Validatoren für
  5. Typen, Bereiche, Patterns und komplexe Strukturen.
  6. """
  7. from __future__ import annotations
  8. import re
  9. from abc import ABC, abstractmethod
  10. from dataclasses import dataclass
  11. from enum import Enum
  12. from typing import Any, Callable, Generic, Sequence, Type, TypeVar
  13. from trixy_core.utils.validation.errors import (
  14. FieldError,
  15. PatternValidationError,
  16. RangeValidationError,
  17. RequiredFieldError,
  18. TypeValidationError,
  19. ValidationError,
  20. )
  21. T = TypeVar("T")
  22. class Validator(ABC, Generic[T]):
  23. """
  24. Abstrakte Basisklasse für alle Validatoren.
  25. Definiert die Schnittstelle für Validierung und
  26. ermöglicht Verkettung von Validatoren.
  27. """
  28. def __init__(
  29. self,
  30. message: str | None = None,
  31. code: str = "invalid",
  32. ) -> None:
  33. """
  34. Initialisiert den Validator.
  35. Args:
  36. message: Optionale benutzerdefinierte Fehlermeldung.
  37. code: Fehlercode für programmatische Behandlung.
  38. """
  39. self._message = message
  40. self._code = code
  41. @property
  42. def message(self) -> str:
  43. """Gibt die Fehlermeldung zurück."""
  44. return self._message or self.default_message
  45. @property
  46. def default_message(self) -> str:
  47. """Standard-Fehlermeldung (kann überschrieben werden)."""
  48. return "Validierung fehlgeschlagen"
  49. @abstractmethod
  50. def validate(self, value: T, field: str = "value") -> None:
  51. """
  52. Validiert einen Wert.
  53. Args:
  54. value: Der zu validierende Wert.
  55. field: Feldname für Fehlermeldungen.
  56. Raises:
  57. ValidationError: Wenn Validierung fehlschlägt.
  58. """
  59. pass
  60. def is_valid(self, value: T) -> bool:
  61. """
  62. Prüft, ob ein Wert gültig ist.
  63. Args:
  64. value: Der zu prüfende Wert.
  65. Returns:
  66. True wenn gültig.
  67. """
  68. try:
  69. self.validate(value)
  70. return True
  71. except ValidationError:
  72. return False
  73. def __call__(self, value: T, field: str = "value") -> None:
  74. """Ermöglicht Aufruf als Funktion."""
  75. self.validate(value, field)
  76. def __and__(self, other: "Validator") -> "AllValidator":
  77. """Kombiniert mit AND-Logik."""
  78. return AllValidator([self, other])
  79. def __or__(self, other: "Validator") -> "AnyValidator":
  80. """Kombiniert mit OR-Logik."""
  81. return AnyValidator([self, other])
  82. class TypeValidator(Validator[Any]):
  83. """
  84. Validator für Typ-Prüfung.
  85. Prüft, ob ein Wert einer bestimmten Typ-Klasse entspricht.
  86. """
  87. def __init__(
  88. self,
  89. expected_type: Type | tuple[Type, ...],
  90. allow_none: bool = False,
  91. message: str | None = None,
  92. ) -> None:
  93. """
  94. Initialisiert den TypeValidator.
  95. Args:
  96. expected_type: Erwarteter Typ oder Tuple von Typen.
  97. allow_none: Ob None erlaubt ist.
  98. message: Optionale Fehlermeldung.
  99. """
  100. super().__init__(message=message, code="type_error")
  101. self.expected_type = expected_type
  102. self.allow_none = allow_none
  103. @property
  104. def default_message(self) -> str:
  105. """Standard-Fehlermeldung."""
  106. if isinstance(self.expected_type, tuple):
  107. type_names = " oder ".join(t.__name__ for t in self.expected_type)
  108. else:
  109. type_names = self.expected_type.__name__
  110. return f"Muss vom Typ {type_names} sein"
  111. def validate(self, value: Any, field: str = "value") -> None:
  112. """Validiert den Typ des Wertes."""
  113. if value is None:
  114. if self.allow_none:
  115. return
  116. raise ValidationError(
  117. message="Wert darf nicht None sein",
  118. field=field,
  119. value=value,
  120. code="null_error",
  121. )
  122. if not isinstance(value, self.expected_type):
  123. raise TypeValidationError(
  124. field=field,
  125. expected_type=self.expected_type, # type: ignore
  126. actual_type=type(value),
  127. value=value,
  128. )
  129. class RangeValidator(Validator[Any]):
  130. """
  131. Validator für numerische Bereiche.
  132. Prüft, ob ein Wert innerhalb eines definierten Bereichs liegt.
  133. """
  134. def __init__(
  135. self,
  136. min_value: Any | None = None,
  137. max_value: Any | None = None,
  138. inclusive_min: bool = True,
  139. inclusive_max: bool = True,
  140. message: str | None = None,
  141. ) -> None:
  142. """
  143. Initialisiert den RangeValidator.
  144. Args:
  145. min_value: Minimaler Wert (None = kein Minimum).
  146. max_value: Maximaler Wert (None = kein Maximum).
  147. inclusive_min: Ob Minimum inklusive ist.
  148. inclusive_max: Ob Maximum inklusive ist.
  149. message: Optionale Fehlermeldung.
  150. """
  151. super().__init__(message=message, code="range_error")
  152. self.min_value = min_value
  153. self.max_value = max_value
  154. self.inclusive_min = inclusive_min
  155. self.inclusive_max = inclusive_max
  156. @property
  157. def default_message(self) -> str:
  158. """Standard-Fehlermeldung."""
  159. parts = []
  160. if self.min_value is not None:
  161. op = ">=" if self.inclusive_min else ">"
  162. parts.append(f"{op} {self.min_value}")
  163. if self.max_value is not None:
  164. op = "<=" if self.inclusive_max else "<"
  165. parts.append(f"{op} {self.max_value}")
  166. return f"Wert muss {' und '.join(parts)} sein"
  167. def validate(self, value: Any, field: str = "value") -> None:
  168. """Validiert, ob der Wert im Bereich liegt."""
  169. if self.min_value is not None:
  170. if self.inclusive_min:
  171. if value < self.min_value:
  172. raise RangeValidationError(
  173. field=field,
  174. value=value,
  175. min_value=self.min_value,
  176. max_value=self.max_value,
  177. )
  178. else:
  179. if value <= self.min_value:
  180. raise RangeValidationError(
  181. field=field,
  182. value=value,
  183. min_value=self.min_value,
  184. max_value=self.max_value,
  185. )
  186. if self.max_value is not None:
  187. if self.inclusive_max:
  188. if value > self.max_value:
  189. raise RangeValidationError(
  190. field=field,
  191. value=value,
  192. min_value=self.min_value,
  193. max_value=self.max_value,
  194. )
  195. else:
  196. if value >= self.max_value:
  197. raise RangeValidationError(
  198. field=field,
  199. value=value,
  200. min_value=self.min_value,
  201. max_value=self.max_value,
  202. )
  203. class PatternValidator(Validator[str]):
  204. """
  205. Validator für Regex-Pattern.
  206. Prüft, ob ein String einem regulären Ausdruck entspricht.
  207. """
  208. def __init__(
  209. self,
  210. pattern: str,
  211. flags: int = 0,
  212. message: str | None = None,
  213. ) -> None:
  214. """
  215. Initialisiert den PatternValidator.
  216. Args:
  217. pattern: Regulärer Ausdruck.
  218. flags: Regex-Flags (z.B. re.IGNORECASE).
  219. message: Optionale Fehlermeldung.
  220. """
  221. super().__init__(message=message, code="pattern_error")
  222. self.pattern = pattern
  223. self._regex = re.compile(pattern, flags)
  224. @property
  225. def default_message(self) -> str:
  226. """Standard-Fehlermeldung."""
  227. return f"Muss dem Pattern '{self.pattern}' entsprechen"
  228. def validate(self, value: str, field: str = "value") -> None:
  229. """Validiert, ob der String dem Pattern entspricht."""
  230. if not self._regex.match(value):
  231. raise PatternValidationError(
  232. field=field,
  233. value=value,
  234. pattern=self.pattern,
  235. )
  236. class LengthValidator(Validator[Any]):
  237. """
  238. Validator für Längen-Prüfung.
  239. Prüft die Länge von Strings, Listen, etc.
  240. """
  241. def __init__(
  242. self,
  243. min_length: int | None = None,
  244. max_length: int | None = None,
  245. exact_length: int | None = None,
  246. message: str | None = None,
  247. ) -> None:
  248. """
  249. Initialisiert den LengthValidator.
  250. Args:
  251. min_length: Minimale Länge.
  252. max_length: Maximale Länge.
  253. exact_length: Exakte Länge (überschreibt min/max).
  254. message: Optionale Fehlermeldung.
  255. """
  256. super().__init__(message=message, code="length_error")
  257. self.min_length = min_length
  258. self.max_length = max_length
  259. self.exact_length = exact_length
  260. @property
  261. def default_message(self) -> str:
  262. """Standard-Fehlermeldung."""
  263. if self.exact_length is not None:
  264. return f"Länge muss genau {self.exact_length} sein"
  265. parts = []
  266. if self.min_length is not None:
  267. parts.append(f"mindestens {self.min_length}")
  268. if self.max_length is not None:
  269. parts.append(f"höchstens {self.max_length}")
  270. return f"Länge muss {' und '.join(parts)} sein"
  271. def validate(self, value: Any, field: str = "value") -> None:
  272. """Validiert die Länge des Wertes."""
  273. try:
  274. length = len(value)
  275. except TypeError:
  276. raise ValidationError(
  277. message="Wert hat keine Länge",
  278. field=field,
  279. value=value,
  280. code="no_length",
  281. )
  282. if self.exact_length is not None:
  283. if length != self.exact_length:
  284. raise ValidationError(
  285. message=f"Länge muss genau {self.exact_length} sein, ist aber {length}",
  286. field=field,
  287. value=value,
  288. code="length_error",
  289. )
  290. else:
  291. if self.min_length is not None and length < self.min_length:
  292. raise ValidationError(
  293. message=f"Länge muss mindestens {self.min_length} sein, ist aber {length}",
  294. field=field,
  295. value=value,
  296. code="min_length_error",
  297. )
  298. if self.max_length is not None and length > self.max_length:
  299. raise ValidationError(
  300. message=f"Länge darf höchstens {self.max_length} sein, ist aber {length}",
  301. field=field,
  302. value=value,
  303. code="max_length_error",
  304. )
  305. class RequiredValidator(Validator[Any]):
  306. """
  307. Validator für Pflichtfelder.
  308. Prüft, ob ein Wert vorhanden und nicht leer ist.
  309. """
  310. def __init__(
  311. self,
  312. allow_empty: bool = False,
  313. allow_whitespace: bool = False,
  314. message: str | None = None,
  315. ) -> None:
  316. """
  317. Initialisiert den RequiredValidator.
  318. Args:
  319. allow_empty: Ob leere Werte ([], {}, "") erlaubt sind.
  320. allow_whitespace: Ob Whitespace-only Strings erlaubt sind.
  321. message: Optionale Fehlermeldung.
  322. """
  323. super().__init__(message=message, code="required")
  324. self.allow_empty = allow_empty
  325. self.allow_whitespace = allow_whitespace
  326. @property
  327. def default_message(self) -> str:
  328. """Standard-Fehlermeldung."""
  329. return "Dieses Feld ist erforderlich"
  330. def validate(self, value: Any, field: str = "value") -> None:
  331. """Validiert, ob der Wert vorhanden ist."""
  332. if value is None:
  333. raise RequiredFieldError(field)
  334. if not self.allow_empty:
  335. try:
  336. if len(value) == 0:
  337. raise ValidationError(
  338. message="Darf nicht leer sein",
  339. field=field,
  340. value=value,
  341. code="empty",
  342. )
  343. except TypeError:
  344. pass # Hat keine Länge, ist OK
  345. if not self.allow_whitespace and isinstance(value, str):
  346. if not value.strip():
  347. raise ValidationError(
  348. message="Darf nicht nur Leerzeichen enthalten",
  349. field=field,
  350. value=value,
  351. code="whitespace_only",
  352. )
  353. class OptionalValidator(Validator[Any]):
  354. """
  355. Validator für optionale Felder mit Fallback.
  356. Erlaubt None und wendet sonst den inneren Validator an.
  357. """
  358. def __init__(
  359. self,
  360. inner_validator: Validator,
  361. default: Any = None,
  362. ) -> None:
  363. """
  364. Initialisiert den OptionalValidator.
  365. Args:
  366. inner_validator: Validator für nicht-None Werte.
  367. default: Standardwert falls None.
  368. """
  369. super().__init__()
  370. self.inner_validator = inner_validator
  371. self.default = default
  372. def validate(self, value: Any, field: str = "value") -> None:
  373. """Validiert den Wert falls nicht None."""
  374. if value is None:
  375. return
  376. self.inner_validator.validate(value, field)
  377. class EnumValidator(Validator[Any]):
  378. """
  379. Validator für Enum-Werte.
  380. Prüft, ob ein Wert ein gültiger Enum-Wert ist.
  381. """
  382. def __init__(
  383. self,
  384. enum_class: Type[Enum] | None = None,
  385. allowed_values: Sequence[Any] | None = None,
  386. message: str | None = None,
  387. ) -> None:
  388. """
  389. Initialisiert den EnumValidator.
  390. Args:
  391. enum_class: Enum-Klasse für gültige Werte.
  392. allowed_values: Alternative: Liste erlaubter Werte.
  393. message: Optionale Fehlermeldung.
  394. """
  395. super().__init__(message=message, code="enum_error")
  396. self.enum_class = enum_class
  397. self.allowed_values = allowed_values
  398. @property
  399. def default_message(self) -> str:
  400. """Standard-Fehlermeldung."""
  401. if self.enum_class:
  402. values = [e.value for e in self.enum_class]
  403. else:
  404. values = list(self.allowed_values or [])
  405. return f"Muss einer von {values} sein"
  406. def validate(self, value: Any, field: str = "value") -> None:
  407. """Validiert, ob der Wert erlaubt ist."""
  408. if self.enum_class:
  409. valid_values = [e.value for e in self.enum_class]
  410. valid_names = [e.name for e in self.enum_class]
  411. if value not in valid_values and value not in valid_names:
  412. if not isinstance(value, self.enum_class):
  413. raise ValidationError(
  414. message=self.message,
  415. field=field,
  416. value=value,
  417. code="enum_error",
  418. )
  419. elif self.allowed_values:
  420. if value not in self.allowed_values:
  421. raise ValidationError(
  422. message=self.message,
  423. field=field,
  424. value=value,
  425. code="enum_error",
  426. )
  427. class ListValidator(Validator[list]):
  428. """
  429. Validator für Listen.
  430. Validiert Listen und deren Elemente.
  431. """
  432. def __init__(
  433. self,
  434. item_validator: Validator | None = None,
  435. min_items: int | None = None,
  436. max_items: int | None = None,
  437. unique: bool = False,
  438. message: str | None = None,
  439. ) -> None:
  440. """
  441. Initialisiert den ListValidator.
  442. Args:
  443. item_validator: Validator für jedes Element.
  444. min_items: Minimale Anzahl Elemente.
  445. max_items: Maximale Anzahl Elemente.
  446. unique: Ob alle Elemente eindeutig sein müssen.
  447. message: Optionale Fehlermeldung.
  448. """
  449. super().__init__(message=message, code="list_error")
  450. self.item_validator = item_validator
  451. self.min_items = min_items
  452. self.max_items = max_items
  453. self.unique = unique
  454. def validate(self, value: list, field: str = "value") -> None:
  455. """Validiert die Liste und deren Elemente."""
  456. if not isinstance(value, (list, tuple)):
  457. raise TypeValidationError(
  458. field=field,
  459. expected_type=list,
  460. actual_type=type(value),
  461. value=value,
  462. )
  463. # Längen-Prüfung
  464. if self.min_items is not None and len(value) < self.min_items:
  465. raise ValidationError(
  466. message=f"Liste muss mindestens {self.min_items} Elemente haben",
  467. field=field,
  468. value=value,
  469. code="min_items",
  470. )
  471. if self.max_items is not None and len(value) > self.max_items:
  472. raise ValidationError(
  473. message=f"Liste darf höchstens {self.max_items} Elemente haben",
  474. field=field,
  475. value=value,
  476. code="max_items",
  477. )
  478. # Eindeutigkeits-Prüfung
  479. if self.unique:
  480. try:
  481. if len(set(value)) != len(value):
  482. raise ValidationError(
  483. message="Liste enthält doppelte Elemente",
  484. field=field,
  485. value=value,
  486. code="not_unique",
  487. )
  488. except TypeError:
  489. # Elemente nicht hashbar
  490. pass
  491. # Element-Validierung
  492. if self.item_validator:
  493. for i, item in enumerate(value):
  494. try:
  495. self.item_validator.validate(item, f"{field}[{i}]")
  496. except ValidationError as e:
  497. raise ValidationError(
  498. message=f"Element {i}: {e.message}",
  499. field=f"{field}[{i}]",
  500. value=item,
  501. code="item_error",
  502. )
  503. class DictValidator(Validator[dict]):
  504. """
  505. Validator für Dictionaries.
  506. Validiert Dictionaries auf Schlüssel und Werte.
  507. """
  508. def __init__(
  509. self,
  510. key_validator: Validator | None = None,
  511. value_validator: Validator | None = None,
  512. required_keys: Sequence[str] | None = None,
  513. allowed_keys: Sequence[str] | None = None,
  514. message: str | None = None,
  515. ) -> None:
  516. """
  517. Initialisiert den DictValidator.
  518. Args:
  519. key_validator: Validator für Schlüssel.
  520. value_validator: Validator für Werte.
  521. required_keys: Liste erforderlicher Schlüssel.
  522. allowed_keys: Liste erlaubter Schlüssel (andere werden abgelehnt).
  523. message: Optionale Fehlermeldung.
  524. """
  525. super().__init__(message=message, code="dict_error")
  526. self.key_validator = key_validator
  527. self.value_validator = value_validator
  528. self.required_keys = set(required_keys) if required_keys else set()
  529. self.allowed_keys = set(allowed_keys) if allowed_keys else None
  530. def validate(self, value: dict, field: str = "value") -> None:
  531. """Validiert das Dictionary."""
  532. if not isinstance(value, dict):
  533. raise TypeValidationError(
  534. field=field,
  535. expected_type=dict,
  536. actual_type=type(value),
  537. value=value,
  538. )
  539. # Erforderliche Schlüssel prüfen
  540. missing = self.required_keys - set(value.keys())
  541. if missing:
  542. raise ValidationError(
  543. message=f"Fehlende Schlüssel: {missing}",
  544. field=field,
  545. value=value,
  546. code="missing_keys",
  547. )
  548. # Erlaubte Schlüssel prüfen
  549. if self.allowed_keys is not None:
  550. extra = set(value.keys()) - self.allowed_keys
  551. if extra:
  552. raise ValidationError(
  553. message=f"Unerlaubte Schlüssel: {extra}",
  554. field=field,
  555. value=value,
  556. code="extra_keys",
  557. )
  558. # Schlüssel und Werte validieren
  559. for key, val in value.items():
  560. if self.key_validator:
  561. self.key_validator.validate(key, f"{field}[key]")
  562. if self.value_validator:
  563. self.value_validator.validate(val, f"{field}[{key!r}]")
  564. class CompositeValidator(Validator[Any]):
  565. """
  566. Basis für zusammengesetzte Validatoren.
  567. """
  568. def __init__(
  569. self,
  570. validators: Sequence[Validator],
  571. message: str | None = None,
  572. ) -> None:
  573. """
  574. Initialisiert den CompositeValidator.
  575. Args:
  576. validators: Liste von Validatoren.
  577. message: Optionale Fehlermeldung.
  578. """
  579. super().__init__(message=message)
  580. self.validators = list(validators)
  581. def add(self, validator: Validator) -> "CompositeValidator":
  582. """Fügt einen Validator hinzu."""
  583. self.validators.append(validator)
  584. return self
  585. class AllValidator(CompositeValidator):
  586. """
  587. Validator der alle Unter-Validatoren prüft (AND-Logik).
  588. """
  589. def validate(self, value: Any, field: str = "value") -> None:
  590. """Validiert mit allen Validatoren."""
  591. for validator in self.validators:
  592. validator.validate(value, field)
  593. class AnyValidator(CompositeValidator):
  594. """
  595. Validator der mindestens einen Unter-Validator prüft (OR-Logik).
  596. """
  597. @property
  598. def default_message(self) -> str:
  599. """Standard-Fehlermeldung."""
  600. return "Keiner der Validatoren war erfolgreich"
  601. def validate(self, value: Any, field: str = "value") -> None:
  602. """Validiert mit mindestens einem Validator."""
  603. errors = []
  604. for validator in self.validators:
  605. try:
  606. validator.validate(value, field)
  607. return # Mindestens einer erfolgreich
  608. except ValidationError as e:
  609. errors.append(e)
  610. # Alle fehlgeschlagen
  611. raise ValidationError(
  612. message=self.message,
  613. field=field,
  614. value=value,
  615. code="all_failed",
  616. )
  617. class ConditionalValidator(Validator[Any]):
  618. """
  619. Validator mit bedingter Logik.
  620. Wendet einen Validator nur an, wenn eine Bedingung erfüllt ist.
  621. """
  622. def __init__(
  623. self,
  624. condition: Callable[[Any], bool],
  625. then_validator: Validator,
  626. else_validator: Validator | None = None,
  627. ) -> None:
  628. """
  629. Initialisiert den ConditionalValidator.
  630. Args:
  631. condition: Funktion, die bestimmt welcher Validator verwendet wird.
  632. then_validator: Validator wenn Bedingung True.
  633. else_validator: Optionaler Validator wenn Bedingung False.
  634. """
  635. super().__init__()
  636. self.condition = condition
  637. self.then_validator = then_validator
  638. self.else_validator = else_validator
  639. def validate(self, value: Any, field: str = "value") -> None:
  640. """Validiert basierend auf der Bedingung."""
  641. if self.condition(value):
  642. self.then_validator.validate(value, field)
  643. elif self.else_validator:
  644. self.else_validator.validate(value, field)
  645. class CallableValidator(Validator[Any]):
  646. """
  647. Validator basierend auf einer benutzerdefinierten Funktion.
  648. """
  649. def __init__(
  650. self,
  651. check: Callable[[Any], bool],
  652. message: str = "Validierung fehlgeschlagen",
  653. code: str = "custom",
  654. ) -> None:
  655. """
  656. Initialisiert den CallableValidator.
  657. Args:
  658. check: Funktion, die True zurückgibt wenn gültig.
  659. message: Fehlermeldung bei Ungültigkeit.
  660. code: Fehlercode.
  661. """
  662. super().__init__(message=message, code=code)
  663. self.check = check
  664. def validate(self, value: Any, field: str = "value") -> None:
  665. """Validiert mit der benutzerdefinierten Funktion."""
  666. if not self.check(value):
  667. raise ValidationError(
  668. message=self.message,
  669. field=field,
  670. value=value,
  671. code=self._code,
  672. )