Skip to content

Commit

Permalink
WIP Change -p so it is possible to early load setuptools plugins
Browse files Browse the repository at this point in the history
-p accepts the option in the form of "module:plugin-name" which
can be used to specify the name of the entry point to early load

This fixes pytest-dev#4718

TODO: docs and tests
  • Loading branch information
nicoddemus committed Feb 6, 2019
1 parent 2461a43 commit 806788f
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 12 deletions.
36 changes: 27 additions & 9 deletions src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,19 +482,35 @@ def consider_preparse(self, args):
continue
self.consider_pluginarg(parg)

def _parse_early_load_arg(self, arg):
original_arg = arg
block = arg.startswith("no:")
if block:
arg = arg[len("no:") :]
fields = arg.split(":")
if len(fields) > 2:
raise UsageError(
'-p expected either plugin module or "mod:name" format, got {!r}'.format(
original_arg
)
)
return block, fields[0], fields[1] if len(fields) == 2 else None

def consider_pluginarg(self, arg):
if arg.startswith("no:"):
name = arg[3:]
block, modname, plugin_name = self._parse_early_load_arg(arg)
if block:
# PR #4304 : remove stepwise if cacheprovider is blocked
if name == "cacheprovider":
if modname == "cacheprovider":
self.set_blocked("stepwise")
self.set_blocked("pytest_stepwise")

self.set_blocked(name)
if not name.startswith("pytest_"):
self.set_blocked("pytest_" + name)
self.set_blocked(modname)
if not modname.startswith("pytest_"):
self.set_blocked("pytest_" + modname)
if plugin_name:
self.set_blocked(plugin_name)
else:
self.import_plugin(arg)
self.import_plugin(modname, plugin_name=plugin_name)

def consider_conftest(self, conftestmodule):
self.register(conftestmodule, name=conftestmodule.__file__)
Expand All @@ -510,7 +526,7 @@ def _import_plugin_specs(self, spec):
for import_spec in plugins:
self.import_plugin(import_spec)

def import_plugin(self, modname):
def import_plugin(self, modname, plugin_name=None):
# most often modname refers to builtin modules, e.g. "pytester",
# "terminal" or "capture". Those plugins are registered under their
# basename for historic purposes but must be imported with the
Expand All @@ -519,6 +535,8 @@ def import_plugin(self, modname):
"module name as text required, got %r" % modname
)
modname = str(modname)
if not plugin_name:
plugin_name = modname
if self.is_blocked(modname) or self.get_plugin(modname) is not None:
return
if modname in builtin_plugins:
Expand Down Expand Up @@ -548,7 +566,7 @@ def import_plugin(self, modname):
)
else:
mod = sys.modules[importspec]
self.register(mod, modname)
self.register(mod, plugin_name)


def _get_plugin_specs_as_list(specs):
Expand Down
33 changes: 33 additions & 0 deletions testing/acceptance_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,39 @@ def test_option(pytestconfig):
assert result.ret == 0
result.stdout.fnmatch_lines(["*1 passed*"])

def test_explicitly_early_load_existing_setuptools_plugin(
self, testdir, monkeypatch
):
# WIP
pkg_resources = pytest.importorskip("pkg_resources")

def my_iter(name):
assert name == "pytest11"
return [EntryPoint()]

class EntryPoint:
name = "mytestplugin"
loaded = False

def load(self):
type(self).loaded = True
return sys.modules[self.name]

@property
def dist(self):
return self

def _get_metadata(self, *args):
return []

class Plugin(object):
pass

monkeypatch.setattr(pkg_resources, "iter_entry_points", my_iter)
monkeypatch.setitem(sys.modules, "mytestplugin", Plugin())
testdir.runpytest("-p", "mytestplugin")
assert EntryPoint.loaded

def test_assertion_magic(self, testdir):
p = testdir.makepyfile(
"""
Expand Down
3 changes: 0 additions & 3 deletions testing/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,6 @@ def test_minus_x_overridden_by_maxfail(self, testdir):
def test_plugin_specify(testdir):
with pytest.raises(ImportError):
testdir.parseconfig("-p", "nqweotexistent")
# pytest.raises(ImportError,
# "config.do_configure(config)"
# )


def test_plugin_already_exists(testdir):
Expand Down

0 comments on commit 806788f

Please sign in to comment.