errors.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. """Pydantic-specific errors."""
  2. from __future__ import annotations as _annotations
  3. import re
  4. from typing_extensions import Literal, Self
  5. from ._migration import getattr_migration
  6. from .version import version_short
  7. __all__ = (
  8. 'PydanticUserError',
  9. 'PydanticUndefinedAnnotation',
  10. 'PydanticImportError',
  11. 'PydanticSchemaGenerationError',
  12. 'PydanticInvalidForJsonSchema',
  13. 'PydanticErrorCodes',
  14. )
  15. # We use this URL to allow for future flexibility about how we host the docs, while allowing for Pydantic
  16. # code in the while with "old" URLs to still work.
  17. # 'u' refers to "user errors" - e.g. errors caused by developers using pydantic, as opposed to validation errors.
  18. DEV_ERROR_DOCS_URL = f'https://errors.pydantic.dev/{version_short()}/u/'
  19. PydanticErrorCodes = Literal[
  20. 'class-not-fully-defined',
  21. 'custom-json-schema',
  22. 'decorator-missing-field',
  23. 'discriminator-no-field',
  24. 'discriminator-alias-type',
  25. 'discriminator-needs-literal',
  26. 'discriminator-alias',
  27. 'discriminator-validator',
  28. 'callable-discriminator-no-tag',
  29. 'typed-dict-version',
  30. 'model-field-overridden',
  31. 'model-field-missing-annotation',
  32. 'config-both',
  33. 'removed-kwargs',
  34. 'invalid-for-json-schema',
  35. 'json-schema-already-used',
  36. 'base-model-instantiated',
  37. 'undefined-annotation',
  38. 'schema-for-unknown-type',
  39. 'import-error',
  40. 'create-model-field-definitions',
  41. 'create-model-config-base',
  42. 'validator-no-fields',
  43. 'validator-invalid-fields',
  44. 'validator-instance-method',
  45. 'root-validator-pre-skip',
  46. 'model-serializer-instance-method',
  47. 'validator-field-config-info',
  48. 'validator-v1-signature',
  49. 'validator-signature',
  50. 'field-serializer-signature',
  51. 'model-serializer-signature',
  52. 'multiple-field-serializers',
  53. 'invalid_annotated_type',
  54. 'type-adapter-config-unused',
  55. 'root-model-extra',
  56. ]
  57. class PydanticErrorMixin:
  58. """A mixin class for common functionality shared by all Pydantic-specific errors.
  59. Attributes:
  60. message: A message describing the error.
  61. code: An optional error code from PydanticErrorCodes enum.
  62. """
  63. def __init__(self, message: str, *, code: PydanticErrorCodes | None) -> None:
  64. self.message = message
  65. self.code = code
  66. def __str__(self) -> str:
  67. if self.code is None:
  68. return self.message
  69. else:
  70. return f'{self.message}\n\nFor further information visit {DEV_ERROR_DOCS_URL}{self.code}'
  71. class PydanticUserError(PydanticErrorMixin, TypeError):
  72. """An error raised due to incorrect use of Pydantic."""
  73. class PydanticUndefinedAnnotation(PydanticErrorMixin, NameError):
  74. """A subclass of `NameError` raised when handling undefined annotations during `CoreSchema` generation.
  75. Attributes:
  76. name: Name of the error.
  77. message: Description of the error.
  78. """
  79. def __init__(self, name: str, message: str) -> None:
  80. self.name = name
  81. super().__init__(message=message, code='undefined-annotation')
  82. @classmethod
  83. def from_name_error(cls, name_error: NameError) -> Self:
  84. """Convert a `NameError` to a `PydanticUndefinedAnnotation` error.
  85. Args:
  86. name_error: `NameError` to be converted.
  87. Returns:
  88. Converted `PydanticUndefinedAnnotation` error.
  89. """
  90. try:
  91. name = name_error.name # type: ignore # python > 3.10
  92. except AttributeError:
  93. name = re.search(r".*'(.+?)'", str(name_error)).group(1) # type: ignore[union-attr]
  94. return cls(name=name, message=str(name_error))
  95. class PydanticImportError(PydanticErrorMixin, ImportError):
  96. """An error raised when an import fails due to module changes between V1 and V2.
  97. Attributes:
  98. message: Description of the error.
  99. """
  100. def __init__(self, message: str) -> None:
  101. super().__init__(message, code='import-error')
  102. class PydanticSchemaGenerationError(PydanticUserError):
  103. """An error raised during failures to generate a `CoreSchema` for some type.
  104. Attributes:
  105. message: Description of the error.
  106. """
  107. def __init__(self, message: str) -> None:
  108. super().__init__(message, code='schema-for-unknown-type')
  109. class PydanticInvalidForJsonSchema(PydanticUserError):
  110. """An error raised during failures to generate a JSON schema for some `CoreSchema`.
  111. Attributes:
  112. message: Description of the error.
  113. """
  114. def __init__(self, message: str) -> None:
  115. super().__init__(message, code='invalid-for-json-schema')
  116. __getattr__ = getattr_migration(__name__)