pytest-dev / pluggy Goto Github PK
View Code? Open in Web Editor NEWA minimalist production ready plugin system
Home Page: https://pluggy.readthedocs.io/en/latest/
License: MIT License
A minimalist production ready plugin system
Home Page: https://pluggy.readthedocs.io/en/latest/
License: MIT License
is triggered by https://github.com/pytest-dev/pluggy/pull/58/files#diff-85f4be4e30ec3b4f3d53843b24d72141R109
@tgoodlet i beleive a test is needed for those edge behaviours
Hi, would it be possible to make a release of 0.5.2 here on GitHub?
I'll put up a test which demonstrates this shortly.
We also don't seem to have any tests which don't also include adding a hookspec
the lack of which is the source of the problem.
Now that #23 has landed it seems fit that we evaluate the _MultiCall
type.
Afaict this class contains a single method execute()
other then __init__
(and __repr__
but who uses it?) and that method was only necessary for the original recursive implementation.
I'm wondering can we simplify the whole thing into a simple function?
Reasons for:
_MultiCall
keeps no state since it's execute method is always called directly after instantiation_MultiCall
instances are never reusedThe latest release of flake8
adds support for E741 ambiguous variable name type errors, resulting in a broken check
tox target.
Hi,
I'm getting lots of these warnings when running some of the pywikibot tests using pytest and python 3.5.
WARNING: C:\Users\a\AppData\Local\Programs\Python\Python35\lib\site-packages\_pytest\vendored_packages\pluggy.py:250: PendingDeprecationWarning: generator 'pytest_pycollect_makeitem' raised StopIteration
wrap_controller.send(call_outcome)
See: https://travis-ci.org/wikimedia/pywikibot-core/jobs/167265098#L493
Currently pluggy._CallOutcome
is implied to be part of the internal api by the leading _
.
In practice it is used by hookwrappers
.
An example:
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
...
The outcome
is accessed directly by the user.
Therefore I propose we expose it correct in plugg.__all__
and expose it in the api reference.
Lines 32 to 34 in 1037dc9
we kept the code for pytest, but we should at least deprecate it and remove the use in future
As per pytest-dev/pytest#2730 0.5.0
broke firstresult
hook wrappers such that a single result is not returned from _Result.get_result()
.
We need a test and fix for this asap!
we should take a look for handling this here as well
instead there should be a clear error on what arguments are missing
While testing pluggy
off the branch from #72, I came across this error:
if '__multicall__' in hookimpl.argnames:
warnings.warn(
"Support for __multicall__ is now deprecated and will be"
"removed in an upcoming release.",
> warnings.DeprecationWarning
)
E AttributeError: module 'warnings' has no attribute 'DeprecationWarning'
Lines 656 to 661 in 557cd3f
And indeed warnings
module doesn't have a DeprecationWarning
.
We should add a test to catch this warnings (and any others we might have).
Currently we have the firstresult
option. An interesting addition would be a way to iterate over the plugins. The big difference to the default of returning all results, is that the consumer can stop iterating at any point. This is useful for things where plugins might cause user interaction. One example is a password hook that tries to get a password from a keychain and if that doesn't work the next plugin is tried, which asks the user for the password in a prompt. With firstresult
we don't get the fallback and with the current default of returning all results, the user would always be prompted, even if the password from the keychain would work.
For func signature inspection in py3 we're supposed to use the new inspect.signature()
.
An example of how to provide dual support for py2/3 can be found here.
As per discussion in pytest-dev/pytest#2716 I want to see if we can avoid self-hosted testing of pluggy
by using relative imports in the test suite. I think the only hurdle will be making tox
work alongside. TravisCI shouldn't have any problems afaik.
So we don't have to manually track versions.
Make sure to use method use by pytest of generating a _version.py
file and importing it to obtain the version; the alternate method of using pkg_resources
does not work from within frozen executables.
For some hooks it would be great if I could make an implementation for it mandatory, so that it doesn't just do nothing but raises an Error when called.
What are your thoughts on that?
As per pytest-dev/pytest#1821 @RonnyPfannschmidt has mentioned it's worth discussing if pluggy.PluginManager
should have a strict mode where every single plugin which is loaded is verified against a spec instead of only performing this validation each time PluginManager.check_pending()
is called.
In pytest
check_pending()
is only done once just prior to the pytest_cmdline_main(config=config)
call meaning unverified hooks can be loaded any time afterwards.
This issue is to open discussion and brainstorming.
There's been some discussion (#15, #23) surrounding performance mostly as it pertains to the _Multicall.execute()
loop.
I propose we add some tests which use pytest-benchmark or something similar to audit changes we make to critical code paths. This encourages being objective about future changes.
You currently can't instantiate a class which defines hook specs prior to loading
import pluggy
hookspec = pluggy.HookspecMarker('example')
class SpecSpace(object):
@hookspec
def myhook(self, stuff):
"""My custom hook spec.
"""
pluggy.PluginManager('example').add_hookspecs(SpecSpace())
because pluggy.varnames()
doesn't successfully detect and remove the self
name.
I realize this is an odd usage (and implied to be illegal based on the argname to add_hookspecs()
) but it is conceivable. A contrived example might be where a user wishes to define the spec and the default hook implementation using the same function:
import pluggy
hookspec = pluggy.HookspecMarker('example')
hookimpl = pluggy.HookimplMarker('example')
class SpecSpace(object):
def __init__(self, arg):
self.arg = arg
@hookimpl
@hookspec
def hook1(self, stuff):
"""My custom hook spec.
"""
if self.arg = 'doggy' and stuff == 'blah':
# do this one thing
else:
# do this other thing
ss = SpecSpace('blah')
pm = pluggy.PluginManager('example')
pm.add_hookspecs(ss)
pm.register(ss)
I guess it's kind of silly...
Either way the implementation of pluggy.varnames
is quite outdated and should be changed to more properly levarage the inspect
module. If we prefer to not ever allow instances then a more explicit error should be thrown in PluginManager.add_hookspecs()
See the latest here: https://readthedocs.org/projects/pluggy/builds/
Looks like the culprit is:
File "conf.py", line 23, in <module>
dist = pkg_resources.get_distribution('pluggy')
So I guess we aren't installing pluggy
prior to docs building? That's a RTD config thing right?
I'd be happy to help with this but I don't have access :(
Once pytest-dev/pytest#2719 get's in we should do a new release and get the fast(er) version of pluggy
's core out in the wild as well as the fixes since 0.4.0
. I wasn't sure if it should be a patch or a full minor.
@hpk42 @nicoddemus @RonnyPfannschmidt I'd be glad to take on this reponsibility from now on if you all are ok with it. I will need to have access to the pypi account however.
Let me know what you guys think!
As the drop from pytest
via pytest-dev/pytest#2812 we can now remove lingering code that is only in place to support old python.
See pytest-dev/pytest#2822 for comparable CI related changes that are likely appropriate.
Some stuff I can think of off hand includes:
{,}
declarations and dict.viewkeys()
.str.format()
method now supports automatic numbering in py2.7+collections.OrderedDict
to simplify some of the internal data structures for managing hooksthis is to help pytest-dev/pytest#1372
the idea is, that if a hook is invoked with a missing, but specced argument, then the default is used instead
so if a hook caller would call hook.pytest_deselected(items=...)' and the hook was defined with
def pytest_deselected(items, reason='No Reason Given)`
then the receivers would receive the defined default reason
in order to support deprecation of such usage we could later devise a mark for deprecated defaults
I just got an email that 0.5.1
is being shipped on NetBSD.
We need to get 0.5.2
out soon!
Things blocking:
I think it should be pretty quick to get these complete :)
As discussed in #62, we should explicitly document how hook call order is done regarding how plugins are registered.
From the top of my head, hooks are called in this order:
try_first
and try_last
);Hi, I'm using py.test and django. Py.test seems to use pluggy behind the scenes.
Can anyone shed some light on this error?
$ py.test
Test session starts (platform: darwin, Python 3.5.2, pytest 3.0.2, pytest-sugar 0.7.1)
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/main.py", line 94, in wrap_session
INTERNALERROR> config.hook.pytest_sessionstart(session=session)
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 724, in __call__
INTERNALERROR> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
INTERNALERROR> _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 596, in execute
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/pytest_sugar.py", line 217, in pytest_sessionstart
INTERNALERROR> lines = self.config.hook.pytest_report_header(config=self.config)
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 724, in __call__
INTERNALERROR> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
INTERNALERROR> _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 593, in execute
INTERNALERROR> args = [all_kwargs[argname] for argname in hook_impl.argnames]
INTERNALERROR> File "/Users/jon/.virtualenvs/webapp/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 593, in <listcomp>
INTERNALERROR> args = [all_kwargs[argname] for argname in hook_impl.argnames]
INTERNALERROR> KeyError: 'startdir'
As per pytest-dev/pytest#2147 we should also move to new-style classes throughout!
in pytest when we use conftests with pytest_plugins,
those specifications are not disabled when using other paths
as such, as soon as trees of conftests that use pytest_plugins, we get a inconsistent dependency state of plugins
additionally some plugins dod epend on other plugins either optionally or directly
experiments and a larger discussion are needed to give this issue the required detail for concrete action
The testing/test_pluggy.py
module is not only a bit long but also overwhelming.
I propose we break up the current organization of as follows:
TestPluginManager
-> test_plugin_manager.py
TestAddMethodOrdering
-> test_add_method_ordering.py
TestMultiCall
-> test_multicall.py
TestHookRelay
-> test_hook_relay.py
TestTracer
-> test_tracer.py
I personally think it just lends to a better immediate understanding of what tests are available/need to be written around each internal component of the pluggy
architecture.
This is a proposal for a very simple new feature. I actually implemented it in a side project pysipp and was thinking it was something we could add to the PluginManger
.
The jist of it is adding a way to temporarily register plugins using a context manager api:
with pluginmanager.register_all([pluginmod1, pluginmod2]) as pm:
#... do stuff that requires above plugins to be active...
# continue with stuff that doesn't require above plugins to be registered.
So it would basically just be adding PluginManager.register_all()
(or whatever name you guys think is best) method that is a simple wrapper around register
/unregister
.
I think I found a good one using a plug symbol and we should be able to insert it using the built-in sidebarlogo
in the layout.html
sphinx-template.
@nicoddemus @hpk42 even as a collaborator I don't seem to be able to modify the title to stick in the docs link :(
I was just thinking it might be a good way to get newcomers more quickly immersed by tempting them with a docs link at the inset ;)
Anyway let me know what you guys think!
i was confronted with code that invoked a hook with positional arguments instead of kwargs,
the default python error in that case left me completely puzzled for a while
a more comprehensible error would be really nice to have
trouble happened when i tried to use a package as a plugin while it had a module named pytest_store
When implementing tox-dev/tox#544 a discussion arose about what it should look like when you output version information about the tool.
So I leave that suggestion here, that pluggy could provide a higher level API to output version information and maybe with different levels of exactness/verbosity (e.g. full paths, vs. just names and versions).
linting is not testing, and we should stop pretending and also add linting/metrics to the GitHub integrations
In pytest-dev/pytest-bdd#224 @soulrebel had an issue when importing pytest_bdd
in his conftest.py
file:
_pytest.vendored_packages.pluggy.PluginValidationError: unknown hook 'pytest_bdd' in plugin <module 'project_qa.tests.functional.conftest' (<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f035b2d4f28>)>
This seems odd - importing a pytest_*
module should work normally, no? Maybe pluggy should at least check that unknown hooks aren't module objects?
The description "as used by py.test" is not very helpful. To be able to compare with other known plugin systems like Trac, SCons , Roundup or Spyder I need to answer the questions:
As discussed in pytest-dev/pytest#2730
As per @nicoddemus's suggestion It'd be good to have an introductory example and a little more excitement there ;)
I am seeing the following error (end of traceback), when running py.test
:
File "…/pytest/_pytest/config.py", line 917, in _preparse
self.pluginmanager.load_setuptools_entrypoints("pytest11")
File "…/pluggy/pluggy.py", line 501, in load_setuptools_entrypoints
plugin = ep.load()
File "…/pyenv/velodrome/lib/python3.4/site-packages/pkg_resources/__init__.py", line 2354, in load
self.require(*args, **kwargs)
File "…/pyenv/velodrome/lib/python3.4/site-packages/pkg_resources/__init__.py", line 2371, in require
items = working_set.resolve(reqs, env, installer)
File "…/pyenv/velodrome/lib/python3.4/site-packages/pkg_resources/__init__.py", line 844, in resolve
raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.VersionConflict: (coverage 4.0b3 (…/pyenv/velodrome/lib/python3.4/site-packages), Requirement.parse('coverage<4.0,>=3.7.1'))
The exception does not provide a hint about the problematic plugin.
As per the comment in pluggy._MultiCall
we should be able to drop the line here. Grepping the pytest
sources reveals that only a few spots still reference it.
This change also allows us to remove the recursion induced by _wrapped_call()
getting passed _MultiCall.execute
. This means we can remove _wrapped_call
and simply loop through hookwrapper pre and post yield
calls at the beginning and end of execute()
. I'd actually be interested to see if contextlib.contextmanager
wrapping could be used directly for this.
Currently the test suite is issuing this warnings:
=============================== warnings summary ===============================
testing/test_method_ordering.py::test_add_tracefuncs[spec-is-class]
/home/travis/build/nicoddemus/pluggy/.tox/py34/lib/python3.4/site-packages/pluggy/__init__.py:678: UserWarning: Argument(s) ('arg',) which are declared in the hookspec can not be found in this hook call
.format(tuple(notincall))
testing/test_method_ordering.py::test_add_tracefuncs[spec-is-instance]
/home/travis/build/nicoddemus/pluggy/.tox/py34/lib/python3.4/site-packages/pluggy/__init__.py:678: UserWarning: Argument(s) ('arg',) which are declared in the hookspec can not be found in this hook call
.format(tuple(notincall))
testing/test_pluginmanager.py::test_call_with_too_few_args
/home/travis/build/nicoddemus/pluggy/.tox/py34/lib/python3.4/site-packages/pluggy/__init__.py:678: UserWarning: Argument(s) ('arg',) which are declared in the hookspec can not be found in this hook call
.format(tuple(notincall))
-- Docs: http://doc.pytest.org/en/latest/warnings.html
Turning them into errors or at least mark them as "known" is a good way to catch incompatibilities early.
Trying to pypi-install (wrapper that generates a debian package from a pip install) I get the following error:
# pypi-install --verbose 5 pluggy
downloading to /tmp/tmpoqv1mk
querying PyPI (https://pypi.python.org/pypi) for package name "pluggy"
found default release: 0.4.0
Traceback (most recent call last):
File "/usr/bin/pypi-install", line 67, in <module>
main()
File "/usr/bin/pypi-install", line 48, in main
allow_unsafe_download=options.allow_unsafe_download)
File "/usr/lib/python2.7/dist-packages/stdeb/downloader.py", line 95, in get_source_tarball
raise ValueError('PYPI returned unsafe url: %r' % download_url)
ValueError: PYPI returned unsafe url: ''
Is there something missing in setup.py ? in the description on pypi ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.