test_details.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import pytest
  2. from pluggy import HookimplMarker
  3. from pluggy import HookspecMarker
  4. from pluggy import PluginManager
  5. hookspec = HookspecMarker("example")
  6. hookimpl = HookimplMarker("example")
  7. def test_parse_hookimpl_override() -> None:
  8. class MyPluginManager(PluginManager):
  9. def parse_hookimpl_opts(self, module_or_class, name):
  10. opts = PluginManager.parse_hookimpl_opts(self, module_or_class, name)
  11. if opts is None:
  12. if name.startswith("x1"):
  13. opts = {} # type: ignore[assignment]
  14. return opts
  15. class Plugin:
  16. def x1meth(self):
  17. pass
  18. @hookimpl(hookwrapper=True, tryfirst=True)
  19. def x1meth2(self):
  20. yield # pragma: no cover
  21. @hookimpl(wrapper=True, trylast=True)
  22. def x1meth3(self):
  23. return (yield) # pragma: no cover
  24. class Spec:
  25. @hookspec
  26. def x1meth(self):
  27. pass
  28. @hookspec
  29. def x1meth2(self):
  30. pass
  31. @hookspec
  32. def x1meth3(self):
  33. pass
  34. pm = MyPluginManager(hookspec.project_name)
  35. pm.register(Plugin())
  36. pm.add_hookspecs(Spec)
  37. hookimpls = pm.hook.x1meth.get_hookimpls()
  38. assert len(hookimpls) == 1
  39. assert not hookimpls[0].hookwrapper
  40. assert not hookimpls[0].wrapper
  41. assert not hookimpls[0].tryfirst
  42. assert not hookimpls[0].trylast
  43. assert not hookimpls[0].optionalhook
  44. hookimpls = pm.hook.x1meth2.get_hookimpls()
  45. assert len(hookimpls) == 1
  46. assert hookimpls[0].hookwrapper
  47. assert not hookimpls[0].wrapper
  48. assert hookimpls[0].tryfirst
  49. hookimpls = pm.hook.x1meth3.get_hookimpls()
  50. assert len(hookimpls) == 1
  51. assert not hookimpls[0].hookwrapper
  52. assert hookimpls[0].wrapper
  53. assert not hookimpls[0].tryfirst
  54. assert hookimpls[0].trylast
  55. def test_warn_when_deprecated_specified(recwarn) -> None:
  56. warning = DeprecationWarning("foo is deprecated")
  57. class Spec:
  58. @hookspec(warn_on_impl=warning)
  59. def foo(self):
  60. pass
  61. class Plugin:
  62. @hookimpl
  63. def foo(self):
  64. pass
  65. pm = PluginManager(hookspec.project_name)
  66. pm.add_hookspecs(Spec)
  67. with pytest.warns(DeprecationWarning) as records:
  68. pm.register(Plugin())
  69. (record,) = records
  70. assert record.message is warning
  71. assert record.filename == Plugin.foo.__code__.co_filename
  72. assert record.lineno == Plugin.foo.__code__.co_firstlineno
  73. def test_plugin_getattr_raises_errors() -> None:
  74. """Pluggy must be able to handle plugins which raise weird exceptions
  75. when getattr() gets called (#11).
  76. """
  77. class DontTouchMe:
  78. def __getattr__(self, x):
  79. raise Exception("can't touch me")
  80. class Module:
  81. pass
  82. module = Module()
  83. module.x = DontTouchMe() # type: ignore[attr-defined]
  84. pm = PluginManager(hookspec.project_name)
  85. # register() would raise an error
  86. pm.register(module, "donttouch")
  87. assert pm.get_plugin("donttouch") is module
  88. def test_not_all_arguments_are_provided_issues_a_warning(pm: PluginManager) -> None:
  89. """Calling a hook without providing all arguments specified in
  90. the hook spec issues a warning."""
  91. class Spec:
  92. @hookspec
  93. def hello(self, arg1, arg2):
  94. pass
  95. @hookspec(historic=True)
  96. def herstory(self, arg1, arg2):
  97. pass
  98. pm.add_hookspecs(Spec)
  99. with pytest.warns(UserWarning, match=r"'arg1', 'arg2'.*cannot be found.*$"):
  100. pm.hook.hello()
  101. with pytest.warns(UserWarning, match=r"'arg2'.*cannot be found.*$"):
  102. pm.hook.hello(arg1=1)
  103. with pytest.warns(UserWarning, match=r"'arg1'.*cannot be found.*$"):
  104. pm.hook.hello(arg2=2)
  105. with pytest.warns(UserWarning, match=r"'arg1', 'arg2'.*cannot be found.*$"):
  106. pm.hook.hello.call_extra([], kwargs=dict())
  107. with pytest.warns(UserWarning, match=r"'arg1', 'arg2'.*cannot be found.*$"):
  108. pm.hook.herstory.call_historic(kwargs=dict())
  109. def test_repr() -> None:
  110. class Plugin:
  111. @hookimpl
  112. def myhook(self):
  113. raise NotImplementedError()
  114. pm = PluginManager(hookspec.project_name)
  115. plugin = Plugin()
  116. pname = pm.register(plugin)
  117. assert repr(pm.hook.myhook.get_hookimpls()[0]) == (
  118. f"<HookImpl plugin_name={pname!r}, plugin={plugin!r}>"
  119. )