Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support defaults via kwargs #43

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

goodboy
Copy link
Contributor

@goodboy goodboy commented Feb 13, 2017

NOTE: this PR builds upon #42 and thus contains its changes as well (for now) but will be rebased after that is merged.

This PR is an initial working implementation what was originally requested by @RonnyPfannschmidt in #15.

I still have concerns with this work (namely the reservations some have had with calling hook functions using f(**kwargs) due to performance) because I do not believe we have properly benchmarked (looked at average versus best case perf) to discard this alternative approach. The use of f(**kwargs) will greatly simplify call loop logic in _MultiCall.execute() which I think is worth acknowledging. I have created #37 to fully assess this performance question.

@nicoddemus @hpk42 I realize #15 is quite lengthy but I believe this work should give us at the least some concrete code and a test to help us agree whether this feature is even something desirable considering its somewhat confusing default arguments precedence order.

As a refresher @RonnyPfannschmidt requested that hookspec keyword argument declarations would be used as defaults to hookimpls which require them when those arguments are not provided at hook call time. Additionally, a hookimpl can also define kwargs with default values which will be used in the case that an older version of the hookspec defining project is being used and thus no defaults are defined on the hookspec. @hpk42 later suggested that such kwargs should only have a default value of None which @RonnyPfannschmidt agreed with.

@goodboy goodboy changed the title Support default via kwargs Support defaults via kwargs Feb 13, 2017
pm.register(Plugin())

# with no spec registered
assert pm.hook.myhook(arg='yeah!')[0] == "my default"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I'm surprised by this behavior; I would not expect a hook caller to be able to make a call without a registered spec. Is this the bug @hpk42 commented here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicoddemus no this is expected if you look at the code. If you want to raise an error due to missing hookspecs then use PluginManager.check_pending().

"""
class Api:
@hookspec
def myhook(self, arg, kwarg="default"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this test I kind agree with the idea of only allowing None as defaults in specs and impls. This is would be less confusing to users and doesn't prevent us to actually allow other values in the future if one of them becomes "obvious".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicoddemus yes this was the consensus prior as well.

My main concern with this is we may end up with lots of if arg is None: checks throughout hookimpls. I guess it serves as an explicit way to show that your hookimpl may be further ahead then the defining project's hookspec?

@goodboy goodboy force-pushed the support_default_via_kwargs branch 3 times, most recently from 1ceb2bf to f9f4eed Compare February 25, 2017 07:11
@@ -749,10 +761,28 @@ def _maybe_apply_history(self, method):
proc(res[0])


class HookSpec(object):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if we decide to abandon this defaults idea I really think we should keep this encapsulation of hookspec objects with a type much like we do with HookImpl. It makes introspection tasks down the road that much simpler.

@goodboy
Copy link
Contributor Author

goodboy commented Feb 25, 2017

@RonnyPfannschmidt @nicoddemus @hpk42 alright now that #42 is in this PR is a lot easier to understand and get back to.

The one outstanding that everyone seemed to agree on is that if we decide to allow default arguments in hookspec and hookimpl then they should only be allowed to have a None default value.

@nicoddemus also clarified terminology nicely in review of #42:

Let's see if we are using the same nomenclature first. Considering this function:

def foobar(x, y, z=4):
    pass  
  • positional arguments: caller passes by position so order matters: foobar(1, 2, 10)
  • keyword arguments: caller passes using keyword syntax so order does not matter: foobar(y=2, x=1, z=10)
  • default arguments: caller does not need to pass them on: foobar(1, 2) # z = 4

On a further note, if we decide this feature is no longer of interest I'd still like to keep a couple things from this PR that are (imho) good improvements. Namely,

  • encapsulating hookspec objects using a HookSpec type
    • makes future introspection tasks much easier
  • avoid monkey patching (eg. _HookCaller._specmodule_or_class)
    • easier to understand code
  • make _MultiCall as hook agnostic as possible
    • maintain a separation of concerns

I would like to get some work on #37 in before moving further with changes here but I want to get everyone thinking about it nonetheless.

Thanks!

Tyler Goodlet added 2 commits July 7, 2017 19:28
Add support for using declared keyword argument values from both
hookspecs and hookimpls. The current logic will inspect the hookimpl
and, if it contains defaults, values will be first looked up from the
caller provided data and if not defined will be taken from the
hookspec's declared defaults. If the spec does not define defaults
the value is taken from the hookimpl's defaults as is expected under
normal function call semantics.

Resolves pytest-dev#15
Verify that defaults declared in hook impls and specs adhere to the
lookup order: call provided value, hook spec default, and finally
falling back to the spec's default value.
@goodboy goodboy force-pushed the support_default_via_kwargs branch from f9f4eed to 9fdd7f3 Compare July 7, 2017 23:28
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Jul 8, 2017
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Aug 29, 2017
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Nov 13, 2017
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Nov 13, 2017
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Aug 8, 2018
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Aug 10, 2018
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Aug 10, 2018
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Aug 10, 2018
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Aug 16, 2018
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Aug 16, 2018
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
goodboy pushed a commit to goodboy/pluggy that referenced this pull request Aug 16, 2018
Allows for easier introspection of spec definitions including function
signatures and hook options. Originally introduced to address pytest-dev#15 and
the accompanying PR (pytest-dev#43) which requires keeping track of spec default
arguments values.
@goodboy
Copy link
Contributor Author

goodboy commented Aug 19, 2018

@RonnyPfannschmidt I'm guess we can close this one then?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants