test_details.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import warnings
  2. import pytest
  3. from pluggy import PluginManager, HookimplMarker, HookspecMarker
  4. hookspec = HookspecMarker("example")
  5. hookimpl = HookimplMarker("example")
  6. def test_parse_hookimpl_override():
  7. class MyPluginManager(PluginManager):
  8. def parse_hookimpl_opts(self, module_or_class, name):
  9. opts = PluginManager.parse_hookimpl_opts(self, module_or_class, name)
  10. if opts is None:
  11. if name.startswith("x1"):
  12. opts = {}
  13. return opts
  14. class Plugin(object):
  15. def x1meth(self):
  16. pass
  17. @hookimpl(hookwrapper=True, tryfirst=True)
  18. def x1meth2(self):
  19. pass
  20. class Spec(object):
  21. @hookspec
  22. def x1meth(self):
  23. pass
  24. @hookspec
  25. def x1meth2(self):
  26. pass
  27. pm = MyPluginManager(hookspec.project_name)
  28. pm.register(Plugin())
  29. pm.add_hookspecs(Spec)
  30. assert not pm.hook.x1meth._nonwrappers[0].hookwrapper
  31. assert not pm.hook.x1meth._nonwrappers[0].tryfirst
  32. assert not pm.hook.x1meth._nonwrappers[0].trylast
  33. assert not pm.hook.x1meth._nonwrappers[0].optionalhook
  34. assert pm.hook.x1meth2._wrappers[0].tryfirst
  35. assert pm.hook.x1meth2._wrappers[0].hookwrapper
  36. def test_warn_when_deprecated_specified(recwarn):
  37. warning = DeprecationWarning("foo is deprecated")
  38. class Spec(object):
  39. @hookspec(warn_on_impl=warning)
  40. def foo(self):
  41. pass
  42. class Plugin(object):
  43. @hookimpl
  44. def foo(self):
  45. pass
  46. pm = PluginManager(hookspec.project_name)
  47. pm.add_hookspecs(Spec)
  48. with pytest.warns(DeprecationWarning) as records:
  49. pm.register(Plugin())
  50. (record,) = records
  51. assert record.message is warning
  52. assert record.filename == Plugin.foo.__code__.co_filename
  53. assert record.lineno == Plugin.foo.__code__.co_firstlineno
  54. def test_plugin_getattr_raises_errors():
  55. """Pluggy must be able to handle plugins which raise weird exceptions
  56. when getattr() gets called (#11).
  57. """
  58. class DontTouchMe(object):
  59. def __getattr__(self, x):
  60. raise Exception("cant touch me")
  61. class Module(object):
  62. pass
  63. module = Module()
  64. module.x = DontTouchMe()
  65. pm = PluginManager(hookspec.project_name)
  66. # register() would raise an error
  67. pm.register(module, "donttouch")
  68. assert pm.get_plugin("donttouch") is module
  69. def test_warning_on_call_vs_hookspec_arg_mismatch():
  70. """Verify that is a hook is called with less arguments then defined in the
  71. spec that a warning is emitted.
  72. """
  73. class Spec:
  74. @hookspec
  75. def myhook(self, arg1, arg2):
  76. pass
  77. class Plugin:
  78. @hookimpl
  79. def myhook(self, arg1):
  80. pass
  81. pm = PluginManager(hookspec.project_name)
  82. pm.register(Plugin())
  83. pm.add_hookspecs(Spec())
  84. with warnings.catch_warnings(record=True) as warns:
  85. warnings.simplefilter("always")
  86. # calling should trigger a warning
  87. pm.hook.myhook(arg1=1)
  88. assert len(warns) == 1
  89. warning = warns[-1]
  90. assert issubclass(warning.category, Warning)
  91. assert "Argument(s) ('arg2',)" in str(warning.message)
  92. def test_repr():
  93. class Plugin:
  94. @hookimpl
  95. def myhook():
  96. raise NotImplementedError()
  97. pm = PluginManager(hookspec.project_name)
  98. plugin = Plugin()
  99. pname = pm.register(plugin)
  100. assert repr(pm.hook.myhook._nonwrappers[0]) == (
  101. "<HookImpl plugin_name=%r, plugin=%r>" % (pname, plugin)
  102. )