inspection.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. # sqlalchemy/inspect.py
  2. # Copyright (C) 2005-2017 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: http://www.opensource.org/licenses/mit-license.php
  7. """The inspection module provides the :func:`.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:`.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:`.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:`.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 :meth:`.Inspector.from_engine`,
  20. :func:`.orm.attributes.instance_state`, :func:`.orm.class_mapper`,
  21. and others. The other is that the return value of :func:`.inspect`
  22. is guaranteed to obey a documented API, thus allowing third party
  23. tools which build on top of SQLAlchemy configurations to be constructed
  24. in a forwards-compatible way.
  25. .. versionadded:: 0.8 The :func:`.inspect` system is introduced
  26. as of version 0.8.
  27. """
  28. from . import util, exc
  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:`.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:`.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 (
  58. reg is None or ret is None
  59. ):
  60. raise exc.NoInspectionAvailable(
  61. "No inspection system is "
  62. "available for object of type %s" %
  63. type_)
  64. return ret
  65. def _inspects(*types):
  66. def decorate(fn_or_cls):
  67. for type_ in types:
  68. if type_ in _registrars:
  69. raise AssertionError(
  70. "Type %s is already "
  71. "registered" % type_)
  72. _registrars[type_] = fn_or_cls
  73. return fn_or_cls
  74. return decorate
  75. def _self_inspects(cls):
  76. _inspects(cls)(True)
  77. return cls