inspection.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. # sqlalchemy/inspect.py
  2. # Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
  3. # <see AUTHORS file>
  4. #
  5. # This module is part of SQLAlchemy and is released under
  6. # the MIT License: https://www.opensource.org/licenses/mit-license.php
  7. """The inspection module provides the :func:`_sa.inspect` function,
  8. which delivers runtime information about a wide variety
  9. of SQLAlchemy objects, both within the Core as well as the
  10. ORM.
  11. The :func:`_sa.inspect` function is the entry point to SQLAlchemy's
  12. public API for viewing the configuration and construction
  13. of in-memory objects. Depending on the type of object
  14. passed to :func:`_sa.inspect`, the return value will either be
  15. a related object which provides a known interface, or in many
  16. cases it will return the object itself.
  17. The rationale for :func:`_sa.inspect` is twofold. One is that
  18. it replaces the need to be aware of a large variety of "information
  19. getting" functions in SQLAlchemy, such as
  20. :meth:`_reflection.Inspector.from_engine` (deprecated in 1.4),
  21. :func:`.orm.attributes.instance_state`, :func:`_orm.class_mapper`,
  22. and others. The other is that the return value of :func:`_sa.inspect`
  23. is guaranteed to obey a documented API, thus allowing third party
  24. tools which build on top of SQLAlchemy configurations to be constructed
  25. in a forwards-compatible way.
  26. """
  27. from . import exc
  28. from . import util
  29. _registrars = util.defaultdict(list)
  30. def inspect(subject, raiseerr=True):
  31. """Produce an inspection object for the given target.
  32. The returned value in some cases may be the
  33. same object as the one given, such as if a
  34. :class:`_orm.Mapper` object is passed. In other
  35. cases, it will be an instance of the registered
  36. inspection type for the given object, such as
  37. if an :class:`_engine.Engine` is passed, an
  38. :class:`_reflection.Inspector` object is returned.
  39. :param subject: the subject to be inspected.
  40. :param raiseerr: When ``True``, if the given subject
  41. does not
  42. correspond to a known SQLAlchemy inspected type,
  43. :class:`sqlalchemy.exc.NoInspectionAvailable`
  44. is raised. If ``False``, ``None`` is returned.
  45. """
  46. type_ = type(subject)
  47. for cls in type_.__mro__:
  48. if cls in _registrars:
  49. reg = _registrars[cls]
  50. if reg is True:
  51. return subject
  52. ret = reg(subject)
  53. if ret is not None:
  54. break
  55. else:
  56. reg = ret = None
  57. if raiseerr and (reg is None or ret is None):
  58. raise exc.NoInspectionAvailable(
  59. "No inspection system is "
  60. "available for object of type %s" % type_
  61. )
  62. return ret
  63. def _inspects(*types):
  64. def decorate(fn_or_cls):
  65. for type_ in types:
  66. if type_ in _registrars:
  67. raise AssertionError(
  68. "Type %s is already " "registered" % type_
  69. )
  70. _registrars[type_] = fn_or_cls
  71. return fn_or_cls
  72. return decorate
  73. def _self_inspects(cls):
  74. _inspects(cls)(True)
  75. return cls