Revert refactor of old-style to new-style classes

As discussed in the mailing list, unfortunately this might break APIs
due to the subtle differences between new and old-style classes (see #2398).

This reverts commit d4afa1554b from PR #2179.
This commit is contained in:
Bruno Oliveira 2017-05-17 18:16:11 -03:00
parent 6f407ef308
commit d86c89e193
16 changed files with 45 additions and 51 deletions

View File

@ -33,9 +33,6 @@ Changes
this is to prepare the removal of preloadconfig in pytest 4.0 this is to prepare the removal of preloadconfig in pytest 4.0
Thanks to `@RonnyPfannschmidt`_ for the PR. Thanks to `@RonnyPfannschmidt`_ for the PR.
* Old-style classes have been changed to new-style classes in order to improve
compatibility with Python 2. Thanks to `@MichalTHEDUDE`_ and `@mandeep`_ for the PR (`#2147`_).
* It is now possible to skip test classes from being collected by setting a * It is now possible to skip test classes from being collected by setting a
``__test__`` attribute to ``False`` in the class body (`#2007`_). Thanks ``__test__`` attribute to ``False`` in the class body (`#2007`_). Thanks
to `@syre`_ for the report and `@lwm`_ for the PR. to `@syre`_ for the report and `@lwm`_ for the PR.
@ -123,7 +120,6 @@ Bug Fixes
.. _#2013: https://github.com/pytest-dev/pytest/issues/2013 .. _#2013: https://github.com/pytest-dev/pytest/issues/2013
.. _#2101: https://github.com/pytest-dev/pytest/pull/2101 .. _#2101: https://github.com/pytest-dev/pytest/pull/2101
.. _#2166: https://github.com/pytest-dev/pytest/pull/2166 .. _#2166: https://github.com/pytest-dev/pytest/pull/2166
.. _#2147: https://github.com/pytest-dev/pytest/issues/2147
.. _#2208: https://github.com/pytest-dev/pytest/issues/2208 .. _#2208: https://github.com/pytest-dev/pytest/issues/2208
.. _#2228: https://github.com/pytest-dev/pytest/issues/2228 .. _#2228: https://github.com/pytest-dev/pytest/issues/2228
.. _#2308: https://github.com/pytest-dev/pytest/issues/2308 .. _#2308: https://github.com/pytest-dev/pytest/issues/2308

View File

@ -62,7 +62,7 @@ import sys
import os import os
from glob import glob from glob import glob
class FastFilesCompleter(object): class FastFilesCompleter:
'Fast file completer class' 'Fast file completer class'
def __init__(self, directories=True): def __init__(self, directories=True):
self.directories = directories self.directories = directories

View File

@ -57,7 +57,7 @@ class DummyRewriteHook(object):
pass pass
class AssertionState(object): class AssertionState:
"""State for the assertion plugin.""" """State for the assertion plugin."""
def __init__(self, config, mode): def __init__(self, config, mode):

View File

@ -87,7 +87,7 @@ class Cache(object):
json.dump(value, f, indent=2, sort_keys=True) json.dump(value, f, indent=2, sort_keys=True)
class LFPlugin(object): class LFPlugin:
""" Plugin which implements the --lf (run last-failing) option """ """ Plugin which implements the --lf (run last-failing) option """
def __init__(self, config): def __init__(self, config):
self.config = config self.config = config

View File

@ -57,7 +57,7 @@ def pytest_load_initial_conftests(early_config, parser, args):
sys.stderr.write(err) sys.stderr.write(err)
class CaptureManager(object): class CaptureManager:
def __init__(self, method): def __init__(self, method):
self._method = method self._method = method
@ -182,7 +182,7 @@ def capfd(request):
return c return c
class CaptureFixture(object): class CaptureFixture:
def __init__(self, captureclass, request): def __init__(self, captureclass, request):
self.captureclass = captureclass self.captureclass = captureclass
self.request = request self.request = request
@ -315,10 +315,10 @@ class MultiCapture(object):
return (self.out.snap() if self.out is not None else "", return (self.out.snap() if self.out is not None else "",
self.err.snap() if self.err is not None else "") self.err.snap() if self.err is not None else "")
class NoCapture(object): class NoCapture:
__init__ = start = done = suspend = resume = lambda *args: None __init__ = start = done = suspend = resume = lambda *args: None
class FDCapture(object): class FDCapture:
""" Capture IO to/from a given os-level filedescriptor. """ """ Capture IO to/from a given os-level filedescriptor. """
def __init__(self, targetfd, tmpfile=None): def __init__(self, targetfd, tmpfile=None):
@ -394,7 +394,7 @@ class FDCapture(object):
os.write(self.targetfd_save, data) os.write(self.targetfd_save, data)
class SysCapture(object): class SysCapture:
def __init__(self, fd, tmpfile=None): def __init__(self, fd, tmpfile=None):
name = patchsysdict[fd] name = patchsysdict[fd]
self._old = getattr(sys, name) self._old = getattr(sys, name)
@ -432,7 +432,7 @@ class SysCapture(object):
self._old.flush() self._old.flush()
class DontReadFromInput(object): class DontReadFromInput:
"""Temporary stub class. Ideally when stdin is accessed, the """Temporary stub class. Ideally when stdin is accessed, the
capturing should be turned off, with possibly all data captured capturing should be turned off, with possibly all data captured
so far sent to the screen. This should be configurable, though, so far sent to the screen. This should be configurable, though,

View File

@ -63,7 +63,7 @@ def main(args=None, plugins=None):
sys.stderr.write("ERROR: %s\n" %(msg,)) sys.stderr.write("ERROR: %s\n" %(msg,))
return 4 return 4
class cmdline(object): # compatibility namespace class cmdline: # compatibility namespace
main = staticmethod(main) main = staticmethod(main)
@ -464,7 +464,7 @@ def _get_plugin_specs_as_list(specs):
return [] return []
class Parser(object): class Parser:
""" Parser for command line arguments and ini-file values. """ Parser for command line arguments and ini-file values.
:ivar extra_info: dict of generic param -> value to display in case :ivar extra_info: dict of generic param -> value to display in case
@ -599,7 +599,7 @@ class ArgumentError(Exception):
return self.msg return self.msg
class Argument(object): class Argument:
"""class that mimics the necessary behaviour of optparse.Option """class that mimics the necessary behaviour of optparse.Option
its currently a least effort implementation its currently a least effort implementation
@ -729,7 +729,7 @@ class Argument(object):
return 'Argument({0})'.format(', '.join(args)) return 'Argument({0})'.format(', '.join(args))
class OptionGroup(object): class OptionGroup:
def __init__(self, name, description="", parser=None): def __init__(self, name, description="", parser=None):
self.name = name self.name = name
self.description = description self.description = description
@ -855,7 +855,7 @@ class CmdOptions(object):
def copy(self): def copy(self):
return CmdOptions(self.__dict__) return CmdOptions(self.__dict__)
class Notset(object): class Notset:
def __repr__(self): def __repr__(self):
return "<NOTSET>" return "<NOTSET>"

View File

@ -40,8 +40,7 @@ def pytest_configure(config):
pytestPDB._pdb_cls = pdb_cls pytestPDB._pdb_cls = pdb_cls
config._cleanup.append(fin) config._cleanup.append(fin)
class pytestPDB:
class pytestPDB(object):
""" Pseudo PDB that defers to the real pdb. """ """ Pseudo PDB that defers to the real pdb. """
_pluginmanager = None _pluginmanager = None
_config = None _config = None
@ -63,7 +62,7 @@ class pytestPDB(object):
cls._pdb_cls().set_trace(frame) cls._pdb_cls().set_trace(frame)
class PdbInvoke(object): class PdbInvoke:
def pytest_exception_interact(self, node, call, report): def pytest_exception_interact(self, node, call, report):
capman = node.config.pluginmanager.getplugin("capturemanager") capman = node.config.pluginmanager.getplugin("capturemanager")
if capman: if capman:

View File

@ -241,7 +241,7 @@ def fillfixtures(function):
def get_direct_param_fixture_func(request): def get_direct_param_fixture_func(request):
return request.param return request.param
class FuncFixtureInfo(object): class FuncFixtureInfo:
def __init__(self, argnames, names_closure, name2fixturedefs): def __init__(self, argnames, names_closure, name2fixturedefs):
self.argnames = argnames self.argnames = argnames
self.names_closure = names_closure self.names_closure = names_closure
@ -439,7 +439,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
fixturedef = self._getnextfixturedef(argname) fixturedef = self._getnextfixturedef(argname)
except FixtureLookupError: except FixtureLookupError:
if argname == "request": if argname == "request":
class PseudoFixtureDef(object): class PseudoFixtureDef:
cached_result = (self, [0], None) cached_result = (self, [0], None)
scope = "function" scope = "function"
return PseudoFixtureDef return PseudoFixtureDef
@ -707,7 +707,7 @@ def call_fixture_func(fixturefunc, request, kwargs):
return res return res
class FixtureDef(object): class FixtureDef:
""" A container for a factory definition. """ """ A container for a factory definition. """
def __init__(self, fixturemanager, baseid, argname, func, scope, params, def __init__(self, fixturemanager, baseid, argname, func, scope, params,
unittest=False, ids=None): unittest=False, ids=None):
@ -806,7 +806,7 @@ def pytest_fixture_setup(fixturedef, request):
return result return result
class FixtureFunctionMarker(object): class FixtureFunctionMarker:
def __init__(self, scope, params, autouse=False, ids=None, name=None): def __init__(self, scope, params, autouse=False, ids=None, name=None):
self.scope = scope self.scope = scope
self.params = params self.params = params
@ -893,7 +893,7 @@ def pytestconfig(request):
return request.config return request.config
class FixtureManager(object): class FixtureManager:
""" """
pytest fixtures definitions and information is stored and managed pytest fixtures definitions and information is stored and managed
from this class. from this class.

View File

@ -190,7 +190,7 @@ def pytest_ignore_collect(path, config):
return False return False
class FSHookProxy(object): class FSHookProxy:
def __init__(self, fspath, pm, remove_mods): def __init__(self, fspath, pm, remove_mods):
self.fspath = fspath self.fspath = fspath
self.pm = pm self.pm = pm

View File

@ -152,7 +152,7 @@ def pytest_collection_modifyitems(items, config):
items[:] = remaining items[:] = remaining
class MarkMapping(object): class MarkMapping:
"""Provides a local mapping for markers where item access """Provides a local mapping for markers where item access
resolves to True if the marker is present. """ resolves to True if the marker is present. """
def __init__(self, keywords): def __init__(self, keywords):
@ -166,7 +166,7 @@ class MarkMapping(object):
return name in self._mymarks return name in self._mymarks
class KeywordMapping(object): class KeywordMapping:
"""Provides a local mapping for keywords. """Provides a local mapping for keywords.
Given a list of names, map any substring of one of these names to True. Given a list of names, map any substring of one of these names to True.
""" """
@ -230,7 +230,7 @@ def pytest_unconfigure(config):
MARK_GEN._config = getattr(config, '_old_mark_config', None) MARK_GEN._config = getattr(config, '_old_mark_config', None)
class MarkGenerator(object): class MarkGenerator:
""" Factory for :class:`MarkDecorator` objects - exposed as """ Factory for :class:`MarkDecorator` objects - exposed as
a ``pytest.mark`` singleton instance. Example:: a ``pytest.mark`` singleton instance. Example::
@ -270,8 +270,7 @@ def istestfunc(func):
return hasattr(func, "__call__") and \ return hasattr(func, "__call__") and \
getattr(func, "__name__", "<lambda>") != "<lambda>" getattr(func, "__name__", "<lambda>") != "<lambda>"
class MarkDecorator:
class MarkDecorator(object):
""" A decorator for test functions and test classes. When applied """ A decorator for test functions and test classes. When applied
it will create :class:`MarkInfo` objects which may be it will create :class:`MarkInfo` objects which may be
:ref:`retrieved by hooks as item keywords <excontrolskip>`. :ref:`retrieved by hooks as item keywords <excontrolskip>`.

View File

@ -89,7 +89,7 @@ def derive_importpath(import_path, raising):
return attr, target return attr, target
class Notset(object): class Notset:
def __repr__(self): def __repr__(self):
return "<notset>" return "<notset>"
@ -97,7 +97,7 @@ class Notset(object):
notset = Notset() notset = Notset()
class MonkeyPatch(object): class MonkeyPatch:
""" Object returned by the ``monkeypatch`` fixture keeping a record of setattr/item/env/syspath changes. """ Object returned by the ``monkeypatch`` fixture keeping a record of setattr/item/env/syspath changes.
""" """

View File

@ -167,7 +167,7 @@ def _pytest(request):
""" """
return PytestArg(request) return PytestArg(request)
class PytestArg(object): class PytestArg:
def __init__(self, request): def __init__(self, request):
self.request = request self.request = request
@ -182,7 +182,7 @@ def get_public_names(l):
return [x for x in l if x[0] != "_"] return [x for x in l if x[0] != "_"]
class ParsedCall(object): class ParsedCall:
def __init__(self, name, kwargs): def __init__(self, name, kwargs):
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
self._name = name self._name = name
@ -193,7 +193,7 @@ class ParsedCall(object):
return "<ParsedCall %r(**%r)>" %(self._name, d) return "<ParsedCall %r(**%r)>" %(self._name, d)
class HookRecorder(object): class HookRecorder:
"""Record all hooks called in a plugin manager. """Record all hooks called in a plugin manager.
This wraps all the hook calls in the plugin manager, recording This wraps all the hook calls in the plugin manager, recording
@ -337,7 +337,7 @@ def testdir(request, tmpdir_factory):
rex_outcome = re.compile(r"(\d+) ([\w-]+)") rex_outcome = re.compile(r"(\d+) ([\w-]+)")
class RunResult(object): class RunResult:
"""The result of running a command. """The result of running a command.
Attributes: Attributes:
@ -383,7 +383,7 @@ class RunResult(object):
class Testdir(object): class Testdir:
"""Temporary test directory with tools to test/run pytest itself. """Temporary test directory with tools to test/run pytest itself.
This is based on the ``tmpdir`` fixture but provides a number of This is based on the ``tmpdir`` fixture but provides a number of
@ -711,7 +711,7 @@ class Testdir(object):
rec = [] rec = []
class Collect(object): class Collect:
def pytest_configure(x, config): def pytest_configure(x, config):
rec.append(self.make_hook_recorder(config.pluginmanager)) rec.append(self.make_hook_recorder(config.pluginmanager))
@ -722,7 +722,7 @@ class Testdir(object):
if len(rec) == 1: if len(rec) == 1:
reprec = rec.pop() reprec = rec.pop()
else: else:
class reprec(object): class reprec:
pass pass
reprec.ret = ret reprec.ret = ret
@ -747,13 +747,13 @@ class Testdir(object):
reprec = self.inline_run(*args, **kwargs) reprec = self.inline_run(*args, **kwargs)
except SystemExit as e: except SystemExit as e:
class reprec(object): class reprec:
ret = e.args[0] ret = e.args[0]
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
class reprec(object): class reprec:
ret = 3 ret = 3
finally: finally:
out, err = capture.readouterr() out, err = capture.readouterr()
@ -1039,7 +1039,7 @@ def getdecoded(out):
py.io.saferepr(out),) py.io.saferepr(out),)
class LineComp(object): class LineComp:
def __init__(self): def __init__(self):
self.stringio = py.io.TextIO() self.stringio = py.io.TextIO()
@ -1055,7 +1055,7 @@ class LineComp(object):
return LineMatcher(lines1).fnmatch_lines(lines2) return LineMatcher(lines1).fnmatch_lines(lines2)
class LineMatcher(object): class LineMatcher:
"""Flexible matching of text. """Flexible matching of text.
This is a convenience class to test large texts like the output of This is a convenience class to test large texts like the output of

View File

@ -49,7 +49,7 @@ def pytest_sessionstart(session):
def pytest_sessionfinish(session): def pytest_sessionfinish(session):
session._setupstate.teardown_all() session._setupstate.teardown_all()
class NodeInfo(object): class NodeInfo:
def __init__(self, location): def __init__(self, location):
self.location = location self.location = location
@ -144,7 +144,7 @@ def call_runtest_hook(item, when, **kwds):
ihook = getattr(item.ihook, hookname) ihook = getattr(item.ihook, hookname)
return CallInfo(lambda: ihook(item=item, **kwds), when=when) return CallInfo(lambda: ihook(item=item, **kwds), when=when)
class CallInfo(object): class CallInfo:
""" Result/Exception info a function invocation. """ """ Result/Exception info a function invocation. """
#: None or ExceptionInfo object. #: None or ExceptionInfo object.
excinfo = None excinfo = None

View File

@ -72,7 +72,7 @@ def xfail(reason=""):
xfail.Exception = XFailed xfail.Exception = XFailed
class MarkEvaluator(object): class MarkEvaluator:
def __init__(self, item, name): def __init__(self, item, name):
self.item = item self.item = item
self.name = name self.name = name

View File

@ -84,7 +84,7 @@ def pytest_report_teststatus(report):
return report.outcome, letter, report.outcome.upper() return report.outcome, letter, report.outcome.upper()
class WarningReport(object): class WarningReport:
""" """
Simple structure to hold warnings information captured by ``pytest_logwarning``. Simple structure to hold warnings information captured by ``pytest_logwarning``.
""" """
@ -118,7 +118,7 @@ class WarningReport(object):
return None return None
class TerminalReporter(object): class TerminalReporter:
def __init__(self, config, file=None): def __init__(self, config, file=None):
import _pytest.config import _pytest.config
self.config = config self.config = config

View File

@ -8,7 +8,7 @@ import py
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
class TempdirFactory(object): class TempdirFactory:
"""Factory for temporary directories under the common base temp directory. """Factory for temporary directories under the common base temp directory.
The base directory can be configured using the ``--basetemp`` option. The base directory can be configured using the ``--basetemp`` option.