Call e-mail hooks that have changed in a backwards compatible manner

Review Request #9250 — Created Oct. 6, 2017 and submitted

Information

Review Board
release-3.0.x
8a0bf5f...

Reviewers

The ReviewEmailHook updated in 3.0b2 with a new argument
(to_submitter_only). The previous hooks did not accept **kwargs, so
calling any existing hook with this new argument will cause an Exception
(and the e-mail will not send). We are now very careful about only
passing in these new arguments when the hook supports them. Otherwise,
we will omit the argument and emit a warning that the hook should accept
**kwargs.

All hook base classes have been updated to accept **kwargs.

Tested with an extension that defined a ReviewEmailHook that did not
accept to_submitter_only. The warning was emitted and the hook did
not cause an exception

Description From Last Updated

F401 'django.utils.six' imported but unused

reviewbotreviewbot

The adding arguments bit repeats.

chipx86chipx86

You can just do kwargs.copy(). No need for the copy module. That said, you can freely modify **kwargs. No need …

chipx86chipx86

This should always warn if argspec.keywords is None. Every single e-mail hook should be updated to take **kwargs. We want …

chipx86chipx86

Rather than type(method.im_self), can you just pass in the hook instance to the method?

chipx86chipx86

This should use DeprecationWarning, rather than a custom warning.

chipx86chipx86
Checks run (1 failed, 1 succeeded)
flake8 failed.
JSHint passed.

flake8

brennie
chipx86
  1. 
      
  2. reviewboard/notifications/email/hooks.py (Diff revision 2)
     
     
     
    Show all issues

    The adding arguments bit repeats.

  3. Show all issues

    You can just do kwargs.copy(). No need for the copy module.

    That said, you can freely modify **kwargs. No need to copy it.

    1. No, I can't, since one method might take kwargs and the other might not. In that case, the latter will have missing args. Splatting a dict does not copy, so we have to copy ourselves.

    2. I'm not sure what you're saying here... _call_hook_compat does get its own copy of **kwargs. It won't modify the version passed in. For instance:

      >>> a = {'a': 1, 'b': 2}
      >>> def foo(**kwargs):
      ...     kwargs.pop('b', None)
      ...     print kwargs
      ...
      >>> foo(**a)
      {'a': 1}
      >>> a
      {'a': 1, 'b': 2}
      >>> def bar(**kwargs):
      ...     foo(**kwargs)
      ...     print kwargs
      ...
      >>> bar(**a)
      {'a': 1}
      {'a': 1, 'b': 2}
      >>> a
      {'a': 1, 'b': 2}
      

      Did I misunderstand?

    3. Ok in my limited testing I was checking the id of the dict passed in and it turns out it is the same but they are not the same dict.

  4. Show all issues

    This should always warn if argspec.keywords is None. Every single e-mail hook should be updated to take **kwargs. We want authors to update their hooks all at once, not just every time we decide to add a parameter. (New extension hook functions that might need new parameters later, like settings or computers, should probably take **kwargs going forward so we minimize running into this.)

    That means the code calling this method needs to always call it. We should have a single code path going through these checks back in filter_email_recipients_from_hooks.

  5. Show all issues

    Rather than type(method.im_self), can you just pass in the hook instance to the method?

  6. Show all issues

    This should use DeprecationWarning, rather than a custom warning.

  7. 
      
brennie
brennie
chipx86
  1. Ship It!
  2. 
      
brennie
Review request changed
Status:
Completed
Change Summary:
Pushed to release-3.0.x (e794a09)