version.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. """The `version` module holds the version information for Pydantic."""
  2. from __future__ import annotations as _annotations
  3. import sys
  4. from pydantic_core import __version__ as __pydantic_core_version__
  5. __all__ = 'VERSION', 'version_info'
  6. VERSION = '2.12.5'
  7. """The version of Pydantic.
  8. This version specifier is guaranteed to be compliant with the [specification],
  9. introduced by [PEP 440].
  10. [specification]: https://packaging.python.org/en/latest/specifications/version-specifiers/
  11. [PEP 440]: https://peps.python.org/pep-0440/
  12. """
  13. # Keep this in sync with the version constraint in the `pyproject.toml` dependencies:
  14. _COMPATIBLE_PYDANTIC_CORE_VERSION = '2.41.5'
  15. def version_short() -> str:
  16. """Return the `major.minor` part of Pydantic version.
  17. It returns '2.1' if Pydantic version is '2.1.1'.
  18. """
  19. return '.'.join(VERSION.split('.')[:2])
  20. def version_info() -> str:
  21. """Return complete version information for Pydantic and its dependencies."""
  22. import importlib.metadata
  23. import platform
  24. from pathlib import Path
  25. import pydantic_core._pydantic_core as pdc
  26. from ._internal import _git as git
  27. # get data about packages that are closely related to pydantic, use pydantic or often conflict with pydantic
  28. package_names = {
  29. 'email-validator',
  30. 'fastapi',
  31. 'mypy',
  32. 'pydantic-extra-types',
  33. 'pydantic-settings',
  34. 'pyright',
  35. 'typing_extensions',
  36. }
  37. related_packages = []
  38. for dist in importlib.metadata.distributions():
  39. name = dist.metadata['Name']
  40. if name in package_names:
  41. related_packages.append(f'{name}-{dist.version}')
  42. pydantic_dir = Path(__file__).parents[1].resolve()
  43. most_recent_commit = (
  44. git.git_revision(pydantic_dir) if git.is_git_repo(pydantic_dir) and git.have_git() else 'unknown'
  45. )
  46. info = {
  47. 'pydantic version': VERSION,
  48. 'pydantic-core version': __pydantic_core_version__,
  49. 'pydantic-core build': getattr(pdc, 'build_info', None) or pdc.build_profile, # pyright: ignore[reportPrivateImportUsage]
  50. 'python version': sys.version,
  51. 'platform': platform.platform(),
  52. 'related packages': ' '.join(related_packages),
  53. 'commit': most_recent_commit,
  54. }
  55. return '\n'.join('{:>30} {}'.format(k + ':', str(v).replace('\n', ' ')) for k, v in info.items())
  56. def check_pydantic_core_version() -> bool:
  57. """Check that the installed `pydantic-core` dependency is compatible."""
  58. return __pydantic_core_version__ == _COMPATIBLE_PYDANTIC_CORE_VERSION
  59. def _ensure_pydantic_core_version() -> None: # pragma: no cover
  60. if not check_pydantic_core_version():
  61. raise_error = True
  62. # Do not raise the error if pydantic is installed in editable mode (i.e. in development):
  63. if sys.version_info >= (3, 13): # origin property added in 3.13
  64. from importlib.metadata import distribution
  65. dist = distribution('pydantic')
  66. if getattr(getattr(dist.origin, 'dir_info', None), 'editable', False):
  67. raise_error = False
  68. if raise_error:
  69. raise SystemError(
  70. f'The installed pydantic-core version ({__pydantic_core_version__}) is incompatible '
  71. f'with the current pydantic version, which requires {_COMPATIBLE_PYDANTIC_CORE_VERSION}. '
  72. "If you encounter this error, make sure that you haven't upgraded pydantic-core manually."
  73. )
  74. def parse_mypy_version(version: str) -> tuple[int, int, int]:
  75. """Parse `mypy` string version to a 3-tuple of ints.
  76. It parses normal version like `1.11.0` and extra info followed by a `+` sign
  77. like `1.11.0+dev.d6d9d8cd4f27c52edac1f537e236ec48a01e54cb.dirty`.
  78. Args:
  79. version: The mypy version string.
  80. Returns:
  81. A triple of ints, e.g. `(1, 11, 0)`.
  82. """
  83. return tuple(map(int, version.partition('+')[0].split('.'))) # pyright: ignore[reportReturnType]