1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/c5689ba15d60/ Changeset: c5689ba15d60 Branch: flake8-clean User: RonnyPfannschmidt Date: 2015-02-22 15:40:42+00:00 Summary: finish flake8 clean of _pytest Affected #: 27 files
diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/assertion/__init__.py --- a/_pytest/assertion/__init__.py +++ b/_pytest/assertion/__init__.py @@ -113,7 +113,7 @@ config=item.config, op=op, left=left, right=right) for new_expl in hook_result: if new_expl: - if (sum(len(p) for p in new_expl[1:]) > 80*8 + if (sum(len(p) for p in new_expl[1:]) > 80 * 8 and item.config.option.verbose < 2): new_expl[1:] = [py.builtin._totext( 'Detailed information truncated, use "-vv" to show')] diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/assertion/reinterpret.py --- a/_pytest/assertion/reinterpret.py +++ b/_pytest/assertion/reinterpret.py @@ -5,7 +5,7 @@ class AssertionError(BuiltinAssertionError): - def __init__(self, *args): # noqa too complex + def __init__(self, *args): BuiltinAssertionError.__init__(self, *args) if args: # on Python2.6 we get len(args)==2 for: assert 0, (x,y) diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/assertion/rewrite.py --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -49,7 +49,7 @@ self.fnpats = session.config.getini("python_files") self.session = session - def find_module(self, name, path=None): # noqa too complex + def find_module(self, name, path=None): if self.session is None: return None sess = self.session @@ -224,7 +224,7 @@ BOM_UTF8 = '\xef\xbb\xbf' -def _rewrite_test(state, fn): # noqa: too complex +def _rewrite_test(state, fn): """Try to read and rewrite *fn* and return the code object.""" try: stat = fn.stat() @@ -506,7 +506,7 @@ """ - def run(self, mod): # noqa: too complex + def run(self, mod): """Find all assert statements in *mod* and rewrite them.""" if not mod.body: # Nothing to do. diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/assertion/util.py --- a/_pytest/assertion/util.py +++ b/_pytest/assertion/util.py @@ -124,7 +124,7 @@ basestring = str -def assertrepr_compare(config, op, left, right): # noqa too complex +def assertrepr_compare(config, op, left, right): """Return specialised explanations for some operators/operands""" width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op left_repr = py.io.saferepr(left, maxsize=int(width / 2)) @@ -184,7 +184,7 @@ return [summary] + explanation -def _diff_text(left, right, verbose=False): # noqa too complex +def _diff_text(left, right, verbose=False): """Return the explanation for the diff between text or bytes Unless --verbose is used this will skip leading and trailing diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -126,7 +126,7 @@ self.resumecapture() self.activate_funcargs(item) yield - #self.deactivate_funcargs() called from suspendcapture() + # self.deactivate_funcargs() called from suspendcapture() self.suspendcapture_item(item, "call") @pytest.mark.hookwrapper @@ -162,6 +162,7 @@ request.node._capfuncarg = c = CaptureFixture(SysCapture) return c + @pytest.fixture def capfd(request): """enables capturing of writes to file descriptors 1 and 2 and makes @@ -182,7 +183,7 @@ def _start(self): self._capture = MultiCapture(out=True, err=True, in_=False, - Capture=self.captureclass) + Capture=self.captureclass) self._capture.start_capturing() def close(self): @@ -219,6 +220,7 @@ class EncodedFile(object): errors = "strict" # possibly needed by py3 code (issue555) + def __init__(self, buffer, encoding): self.buffer = buffer self.encoding = encoding @@ -299,9 +301,11 @@ return (self.out.snap() if self.out is not None else "", self.err.snap() if self.err is not None else "") + class NoCapture: __init__ = start = done = suspend = resume = lambda *args: None + class FDCapture: """ Capture IO to/from a given os-level filedescriptor. """ @@ -374,7 +378,8 @@ def writeorg(self, data): """ write to original file descriptor. """ if py.builtin._istext(data): - data = data.encode("utf8") # XXX use encoding of original stream + # XXX use encoding of original stream + data = data.encode("utf8") os.write(self.targetfd_save, data) diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -7,12 +7,14 @@ import py # DON't import pytest here because it causes import cycle troubles -import sys, os -from _pytest import hookspec # the extension point definitions +import sys +import os +# the extension point definitions +from _pytest import hookspec from _pytest.core import PluginManager + # pytest startup -# class ConftestImportFailure(Exception): def __init__(self, path, excinfo): Exception.__init__(self, path, excinfo) @@ -40,33 +42,38 @@ else: return config.hook.pytest_cmdline_main(config=config) + class cmdline: # compatibility namespace main = staticmethod(main) + class UsageError(Exception): """ error in pytest usage or invocation""" _preinit = [] default_plugins = ( - "mark main terminal runner python pdb unittest capture skipping " - "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript " - "junitxml resultlog doctest").split() + "mark main terminal runner python pdb unittest capture skipping " + "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript " + "junitxml resultlog doctest").split() + def _preloadplugins(): assert not _preinit _preinit.append(get_plugin_manager()) + def get_plugin_manager(): if _preinit: return _preinit.pop(0) # subsequent calls to main will create a fresh instance pluginmanager = PytestPluginManager() - pluginmanager.config = Config(pluginmanager) # XXX attr needed? + pluginmanager.config = Config(pluginmanager) # XXX attr needed? for spec in default_plugins: pluginmanager.import_plugin(spec) return pluginmanager + def _prepareconfig(args=None, plugins=None): if args is None: args = sys.argv[1:] @@ -82,11 +89,12 @@ for plugin in plugins: pluginmanager.register(plugin) return pluginmanager.hook.pytest_cmdline_parse( - pluginmanager=pluginmanager, args=args) + pluginmanager=pluginmanager, args=args) except Exception: pluginmanager.ensure_shutdown() raise + class PytestPluginManager(PluginManager): def __init__(self, hookspecs=[hookspec]): super(PytestPluginManager, self).__init__(hookspecs=hookspecs) @@ -101,10 +109,12 @@ self.set_tracing(err.write) def pytest_configure(self, config): - config.addinivalue_line("markers", + config.addinivalue_line( + "markers", "tryfirst: mark a hook implementation function such that the " "plugin machinery will try to call it first/as early as possible.") - config.addinivalue_line("markers", + config.addinivalue_line( + "markers", "trylast: mark a hook implementation function such that the " "plugin machinery will try to call it last/as late as possible.") for warning in self._warnings: @@ -147,7 +157,7 @@ for i, grp in enumerate(self._groups): if grp.name == after: break - self._groups.insert(i+1, group) + self._groups.insert(i + 1, group) return group def addoption(self, *opts, **attrs): @@ -185,7 +195,8 @@ a = option.attrs() arggroup.add_argument(*n, **a) # bash like autocompletion for dirs (appending '/') - optparser.add_argument(FILE_OR_DIR, nargs='*').completer=filescompleter + optparser.add_argument( + FILE_OR_DIR, nargs='*').completer = filescompleter return optparser def parse_setoption(self, args, option): @@ -203,7 +214,8 @@ """ register an ini-file option. :name: name of the ini-variable - :type: type of the variable, can be ``pathlist``, ``args`` or ``linelist``. + :type: type of the variable, + can be ``pathlist``, ``args`` or ``linelist``. :default: default value if no ini-file option exists but is queried. The value of ini-variables can be retrieved via a call to @@ -236,7 +248,8 @@ _typ_map = { 'int': int, 'string': str, - } + } + # enable after some grace period for plugin writers TYPE_WARN = False @@ -321,7 +334,7 @@ if self._attrs.get('help'): a = self._attrs['help'] a = a.replace('%default', '%(default)s') - #a = a.replace('%prog', '%(prog)s') + # a = a.replace('%prog', '%(prog)s') self._attrs['help'] = a return self._attrs @@ -401,8 +414,9 @@ class MyOptionParser(argparse.ArgumentParser): def __init__(self, parser): self._parser = parser - argparse.ArgumentParser.__init__(self, usage=parser._usage, - add_help=False, formatter_class=DropShorterLongHelpFormatter) + argparse.ArgumentParser.__init__( + self, usage=parser._usage, add_help=False, + formatter_class=DropShorterLongHelpFormatter) def parse_args(self, args=None, namespace=None): """allow splitting of positional arguments""" @@ -415,6 +429,7 @@ getattr(args, FILE_OR_DIR).extend(argv) return args + class DropShorterLongHelpFormatter(argparse.HelpFormatter): """shorten help for long options that differ only in extra hyphens @@ -426,18 +441,19 @@ """ def _format_action_invocation(self, action): orgstr = argparse.HelpFormatter._format_action_invocation(self, action) - if orgstr and orgstr[0] != '-': # only optional arguments + if orgstr and orgstr[0] != '-': # only optional arguments return orgstr res = getattr(action, '_formatted_action_invocation', None) if res: return res options = orgstr.split(', ') - if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2): + if len(options) == 2 and \ + (len(options[0]) == 2 or len(options[1]) == 2): # a shortcut for '-h, --help' or '--abc', '-a' action._formatted_action_invocation = orgstr return orgstr return_list = [] - option_map = getattr(action, 'map_long_option', {}) + option_map = getattr(action, 'map_long_option', {}) if option_map is None: option_map = {} short_long = {} @@ -455,7 +471,7 @@ short_long[shortened] = xxoption # now short_long has been filled out to the longest with dashes # **and** we keep the right option ordering from add_argument - for option in options: # + for option in options: if len(option) == 2 or option[2] == ' ': return_list.append(option) if option[2:] == short_long.get(option.replace('-', '')): @@ -484,7 +500,7 @@ """ current = py.path.local() self._confcutdir = current.join(namespace.confcutdir, abs=True) \ - if namespace.confcutdir else None + if namespace.confcutdir else None testpaths = namespace.file_or_dir foundanchor = False for path in testpaths: @@ -494,7 +510,7 @@ if i != -1: path = path[:i] anchor = current.join(path, abs=1) - if exists(anchor): # we found some file object + if exists(anchor): # we found some file object self._try_load_conftest(anchor) foundanchor = True if not foundanchor: @@ -561,12 +577,16 @@ except KeyError: pass + class CmdOptions(object): """ holds cmdline options as attributes.""" + def __init__(self, **kwargs): self.__dict__.update(kwargs) + def __repr__(self): - return "<CmdOptions %r>" %(self.__dict__,) + return "<CmdOptions %r>" % (self.__dict__,) + class Notset: def __repr__(self): @@ -574,12 +594,15 @@ notset = Notset() FILE_OR_DIR = 'file_or_dir' + + class Config(object): """ access to configuration values, pluginmanager and plugin hooks. """ def __init__(self, pluginmanager): #: access to command line option as attributes. - #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead + #: (deprecated), use + #: :py:func:`getoption() <_pytest.config.Config.getoption>` instead self.option = CmdOptions() _a = FILE_OR_DIR self._parser = Parser( @@ -646,7 +669,8 @@ style = "long" else: style = "native" - excrepr = excinfo.getrepr(funcargs=True, + excrepr = excinfo.getrepr( + funcargs=True, showlocals=getattr(option, 'showlocals', False), style=style, ) @@ -654,10 +678,9 @@ excinfo=excinfo) if not py.builtin.any(res): for line in str(excrepr).split("\n"): - sys.stderr.write("INTERNALERROR> %s\n" %line) + sys.stderr.write("INTERNALERROR> %s\n" % line) sys.stderr.flush() - @classmethod def fromdictargs(cls, option_dict, args): """ constructor useable for subprocesses. """ @@ -670,7 +693,7 @@ return config def _onimportconftest(self, conftestmodule): - self.trace("loaded conftestmodule %r" %(conftestmodule,)) + self.trace("loaded conftestmodule %r" % (conftestmodule,)) self.pluginmanager.consider_conftest(conftestmodule) def _processopt(self, opt): @@ -683,7 +706,7 @@ def _getmatchingplugins(self, fspath): return self.pluginmanager._plugins + \ - self._conftest.getconftestmodules(fspath) + self._conftest.getconftestmodules(fspath) def pytest_load_initial_conftests(self, early_config): self._conftest.setinitial(early_config.known_args_namespace) @@ -713,15 +736,15 @@ self.pluginmanager.consider_env() self.known_args_namespace = ns = self._parser.parse_known_args(args) try: - self.hook.pytest_load_initial_conftests(early_config=self, - args=args, parser=self._parser) + self.hook.pytest_load_initial_conftests( + early_config=self, args=args, parser=self._parser) except ConftestImportFailure: e = sys.exc_info()[1] if ns.help or ns.version: # we don't want to prevent --help/--version to work # so just let is pass and print a warning at the end self.pluginmanager._warnings.append( - "could not load initial conftests (%s)\n" % e.path) + "could not load initial conftests (%s)\n" % e.path) else: raise @@ -733,14 +756,15 @@ myver = pytest.__version__.split(".") if myver < ver: raise pytest.UsageError( - "%s:%d: requires pytest-%s, actual pytest-%s'" %( - self.inicfg.config.path, self.inicfg.lineof('minversion'), - minver, pytest.__version__)) + "%s:%d: requires pytest-%s, actual pytest-%s'" % ( + self.inicfg.config.path, + self.inicfg.lineof('minversion'), + minver, pytest.__version__)) def parse(self, args): # parse given cmdline arguments into this config object. assert not hasattr(self, 'args'), ( - "can only parse cmdline args at most once per Config object") + "can only parse cmdline args at most once per Config object") self._origargs = args self._preparse(args) # XXX deprecated hook: @@ -756,7 +780,7 @@ the first line in its value. """ x = self.getini(name) assert isinstance(x, list) - x.append(line) # modifies the cached list inline + x.append(line) # modifies the cached list inline def getini(self, name): """ return configuration value from an :ref:`ini file <inifiles>`. If the @@ -773,7 +797,7 @@ try: description, type, default = self._parser._inidict[name] except KeyError: - raise ValueError("unknown configuration value: %r" %(name,)) + raise ValueError("unknown configuration value: %r" % (name,)) try: value = self.inicfg[name] except KeyError: @@ -791,7 +815,8 @@ elif type == "args": return shlex.split(value) elif type == "linelist": - return [t for t in map(lambda x: x.strip(), value.split("\n")) if t] + return [t for t in + map(lambda x: x.strip(), value.split("\n")) if t] else: assert type is None return value @@ -830,7 +855,7 @@ return default if skip: import pytest - pytest.skip("no %r option found" %(name,)) + pytest.skip("no %r option found" % (name,)) raise ValueError("no option named %r" % (name,)) def getvalue(self, name, path=None): @@ -841,12 +866,14 @@ """ (deprecated, use getoption(skip=True)) """ return self.getoption(name, skip=True) + def exists(path, ignore=EnvironmentError): try: return path.check() except ignore: return False + def getcfg(args, inibasenames): args = [x for x in args if not str(x).startswith("-")] if not args: @@ -879,6 +906,6 @@ else: setattr(obj, name, value) obj.__all__.append(name) - #if obj != pytest: + # if obj != pytest: # pytest.__all__.append(name) setattr(pytest, name, value) diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/core.py --- a/_pytest/core.py +++ b/_pytest/core.py @@ -192,7 +192,7 @@ name = name or getattr(plugin, '__name__', str(id(plugin))) if self.isregistered(plugin, name): raise ValueError("Plugin already registered: %s=%s\n%s" % ( - name, plugin, self._name2plugin)) + name, plugin, self._name2plugin)) # self.trace("registering", name, plugin) reg = getattr(self, "_registercallback", None) if reg is not None: @@ -414,7 +414,7 @@ return self.results -def varnames(func, startindex=None): # noqa - complexity 13 +def varnames(func, startindex=None): """ return argument name tuple for a function, method, class or callable. In case of a class, its "__init__" method is considered. @@ -548,7 +548,7 @@ def isgenerichook(name): return name == "pytest_plugins" or \ - name.startswith("pytest_funcarg__") + name.startswith("pytest_funcarg__") def formatdef(func): diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/doctest.py --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -1,41 +1,51 @@ """ discover and run doctests in modules and test files.""" from __future__ import absolute_import import traceback -import pytest, py +import pytest +import py from _pytest.python import FixtureRequest, FuncFixtureInfo from py._code.code import TerminalRepr, ReprFileLocation + def pytest_addoption(parser): - parser.addini('doctest_optionflags', 'option flags for doctests', + parser.addini( + 'doctest_optionflags', 'option flags for doctests', type="args", default=["ELLIPSIS"]) group = parser.getgroup("collect") - group.addoption("--doctest-modules", + group.addoption( + "--doctest-modules", action="store_true", default=False, help="run doctests in all .py modules", dest="doctestmodules") - group.addoption("--doctest-glob", + group.addoption( + "--doctest-glob", action="store", default="test*.txt", metavar="pat", help="doctests file matching pattern, default: test*.txt", dest="doctestglob") + def pytest_collect_file(path, parent): config = parent.config if path.ext == ".py": if config.option.doctestmodules: return DoctestModule(path, parent) - elif (path.ext in ('.txt', '.rst') and parent.session.isinitpath(path)) or \ - path.check(fnmatch=config.getvalue("doctestglob")): + elif (path.ext in ('.txt', '.rst') + and parent.session.isinitpath(path)) or \ + path.check(fnmatch=config.getvalue("doctestglob")): return DoctestTextfile(path, parent) + class ReprFailDoctest(TerminalRepr): def __init__(self, reprlocation, lines): self.reprlocation = reprlocation self.lines = lines + def toterminal(self, tw): for line in self.lines: tw.line(line) self.reprlocation.toterminal(tw) + class DoctestItem(pytest.Item): def __init__(self, name, parent, runner=None, dtest=None): super(DoctestItem, self).__init__(name, parent) @@ -64,23 +74,24 @@ filelines = py.path.local(filename).readlines(cr=0) lines = [] if lineno is not None: - i = max(test.lineno, max(0, lineno - 10)) # XXX? + i = max(test.lineno, max(0, lineno - 10)) # XXX? for line in filelines[i:lineno]: - lines.append("%03d %s" % (i+1, line)) + lines.append("%03d %s" % (i + 1, line)) i += 1 else: - lines.append('EXAMPLE LOCATION UNKNOWN, not showing all tests of that example') + lines.append('EXAMPLE LOCATION UNKNOWN, ' + 'not showing all tests of that example') indent = '>>>' for line in example.source.splitlines(): lines.append('??? %s %s' % (indent, line)) indent = '...' if excinfo.errisinstance(doctest.DocTestFailure): - lines += checker.output_difference(example, - doctestfailure.got, REPORT_UDIFF).split("\n") + lines += checker.output_difference( + example, + doctestfailure.got, REPORT_UDIFF).split("\n") else: inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info) - lines += ["UNEXPECTED EXCEPTION: %s" % - repr(inner_excinfo.value)] + lines += ["UNEXPECTED EXCEPTION: %r" % (inner_excinfo.value,)] lines += traceback.format_exception(*excinfo.value.exc_info) return ReprFailDoctest(reprlocation, lines) else: @@ -89,6 +100,7 @@ def reportinfo(self): return self.fspath, None, "[doctest] %s" % self.name + def _get_flag_lookup(): import doctest return dict(DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1, @@ -98,6 +110,7 @@ IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL, COMPARISON_FLAGS=doctest.COMPARISON_FLAGS) + def get_optionflags(parent): optionflags_str = parent.config.getini("doctest_optionflags") flag_lookup_table = _get_flag_lookup() @@ -106,12 +119,14 @@ flag_acc |= flag_lookup_table[flag] return flag_acc + class DoctestTextfile(DoctestItem, pytest.File): def runtest(self): import doctest # satisfy `FixtureRequest` constructor... self.funcargs = {} fm = self.session._fixturemanager + def func(): pass self._fixtureinfo = fm.getfixtureinfo(node=self, func=func, @@ -124,6 +139,7 @@ extraglobs=dict(getfixture=fixture_request.getfuncargvalue), raise_on_error=True, verbose=0) + class DoctestModule(pytest.File): def collect(self): import doctest @@ -138,9 +154,9 @@ doctest_globals = dict(getfixture=fixture_request.getfuncargvalue) # uses internal doctest module parsing mechanism finder = doctest.DocTestFinder() - optionflags= get_optionflags(self) + optionflags = get_optionflags(self) runner = doctest.DebugRunner(verbose=0, optionflags=optionflags) for test in finder.find(module, module.__name__, extraglobs=doctest_globals): - if test.examples: # skip empty doctests + if test.examples: # skip empty doctests yield DoctestItem(test.name, self, runner, test) diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/genscript.py --- a/_pytest/genscript.py +++ b/_pytest/genscript.py @@ -8,11 +8,10 @@ import _pytest - def find_toplevel(name): for syspath in sys.path: base = py.path.local(syspath) - lib = base/name + lib = base / name if lib.check(dir=1): return lib mod = base.join("%s.py" % name) @@ -20,23 +19,28 @@ return mod raise LookupError(name) + def pkgname(toplevel, rootpath, path): parts = path.parts()[len(rootpath.parts()):] return '.'.join([toplevel] + [x.purebasename for x in parts]) + def pkg_to_mapping(name): toplevel = find_toplevel(name) name2src = {} - if toplevel.check(file=1): # module + if toplevel.check(file=1): # module name2src[toplevel.purebasename] = toplevel.read() - else: # package + else: # package for pyfile in toplevel.visit('*.py'): pkg = pkgname(name, toplevel, pyfile) name2src[pkg] = pyfile.read() return name2src + def compress_mapping(mapping): - import base64, pickle, zlib + import base64 + import pickle + import zlib data = pickle.dumps(mapping, 2) data = zlib.compress(data, 9) data = base64.encodestring(data) @@ -50,6 +54,7 @@ mapping.update(pkg_to_mapping(name)) return compress_mapping(mapping) + def generate_script(entry, packages): data = compress_packages(packages) tmpl = py.path.local(__file__).dirpath().join('standalonetemplate.py') @@ -61,16 +66,18 @@ def pytest_addoption(parser): group = parser.getgroup("debugconfig") - group.addoption("--genscript", action="store", default=None, + group.addoption( + "--genscript", action="store", default=None, dest="genscript", metavar="path", help="create standalone pytest script at given target path.") + def pytest_cmdline_main(config): genscript = config.getvalue("genscript") if genscript: tw = py.io.TerminalWriter() - deps = ['py', '_pytest', 'pytest'] - if sys.version_info < (2,7): + deps = ['py', '_pytest', 'pytest'] + if sys.version_info < (2, 7): deps.append("argparse") tw.line("generated script will run on python2.6-python3.3++") else: @@ -121,7 +128,9 @@ path = package for _, name, is_package in pkgutil.iter_modules([path]): if is_package: - for m in _iter_all_modules(os.path.join(path, name), prefix=name + '.'): + for m in _iter_all_modules( + os.path.join(path, name), + prefix=name + '.'): yield prefix + m else: yield prefix + name diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -1,25 +1,32 @@ """ version info, help messages, tracing configuration. """ import py import pytest -import os, sys +import os +import sys + def pytest_addoption(parser): group = parser.getgroup('debugconfig') - group.addoption('--version', action="store_true", - help="display pytest lib version and import information.") - group._addoption("-h", "--help", action="store_true", dest="help", - help="show help message and configuration info") - group._addoption('-p', action="append", dest="plugins", default = [], - metavar="name", - help="early-load given plugin (multi-allowed). " - "To avoid loading of plugins, use the `no:` prefix, e.g. " - "`no:doctest`.") - group.addoption('--traceconfig', '--trace-config', - action="store_true", default=False, - help="trace considerations of conftest.py files."), - group.addoption('--debug', - action="store_true", dest="debug", default=False, - help="store internal tracing debug information in 'pytestdebug.log'.") + group.addoption( + '--version', action="store_true", + help="display pytest lib version and import information.") + group._addoption( + "-h", "--help", action="store_true", dest="help", + help="show help message and configuration info") + group._addoption( + '-p', action="append", dest="plugins", default=[], + metavar="name", + help="early-load given plugin (multi-allowed). " + "To avoid loading of plugins, use the `no:` prefix, e.g. " + "`no:doctest`.") + group.addoption( + '--traceconfig', '--trace-config', + action="store_true", default=False, + help="trace considerations of conftest.py files."), + group.addoption( + '--debug', + action="store_true", dest="debug", default=False, + help="store internal tracing debug information in 'pytestdebug.log'.") @pytest.mark.hookwrapper @@ -31,19 +38,20 @@ f = open(path, 'w') config._debugfile = f f.write("versions pytest-%s, py-%s, " - "python-%s\ncwd=%s\nargs=%s\n\n" %( - pytest.__version__, py.__version__, - ".".join(map(str, sys.version_info)), - os.getcwd(), config._origargs)) + "python-%s\ncwd=%s\nargs=%s\n\n" % ( + pytest.__version__, py.__version__, + ".".join(map(str, sys.version_info)), + os.getcwd(), config._origargs)) config.pluginmanager.set_tracing(f.write) sys.stderr.write("writing pytestdebug information to %s\n" % path) + @pytest.mark.trylast def pytest_unconfigure(config): if hasattr(config, '_debugfile'): config._debugfile.close() sys.stderr.write("wrote pytestdebug information to %s\n" % - config._debugfile.name) + config._debugfile.name) config.trace.root.setwriter(None) @@ -51,7 +59,7 @@ if config.option.version: p = py.path.local(pytest.__file__) sys.stderr.write("This is pytest version %s, imported from %s\n" % - (pytest.__version__, p)) + (pytest.__version__, p)) plugininfo = getpluginversioninfo(config) if plugininfo: for line in plugininfo: @@ -63,12 +71,13 @@ config.do_unconfigure() return 0 + def showhelp(config): tw = py.io.TerminalWriter() tw.write(config._parser.optparser.format_help()) tw.line() tw.line() - #tw.sep( "=", "config file settings") + # tw.sep( "=", "config file settings") tw.line("[pytest] ini-options in the next " "pytest.ini|tox.ini|setup.cfg file:") tw.line() @@ -78,11 +87,12 @@ if type is None: type = "string" spec = "%s (%s)" % (name, type) - line = " %-24s %s" %(spec, help) + line = " %-24s %s" % (spec, help) tw.line(line[:tw.fullwidth]) - tw.line() ; tw.line() - #tw.sep("=") + tw.line() + tw.line() + # tw.sep("=") tw.line("to see available markers type: py.test --markers") tw.line("to see available fixtures type: py.test --fixtures") tw.line("(shown according to specified file_or_dir or current dir " @@ -96,6 +106,7 @@ ('pytest_plugins', 'list of plugin names to load'), ] + def getpluginversioninfo(config): lines = [] plugininfo = config.pluginmanager._plugin_distinfo @@ -107,11 +118,12 @@ lines.append(" " + content) return lines + def pytest_report_header(config): lines = [] if config.option.debug or config.option.traceconfig: - lines.append("using: pytest-%s pylib-%s" % - (pytest.__version__,py.__version__)) + lines.append( + "using: pytest-%s pylib-%s" % (pytest.__version__, py.__version__)) verinfo = getpluginversioninfo(config) if verinfo: @@ -125,7 +137,5 @@ r = plugin.__file__ else: r = repr(plugin) - lines.append(" %-20s: %s" %(name, r)) + lines.append(" %-20s: %s" % (name, r)) return lines - - diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/hookspec.py --- a/_pytest/hookspec.py +++ b/_pytest/hookspec.py @@ -1,9 +1,11 @@ -""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """ +""" hook specifications for pytest plugins, +invoked from main.py and builtin plugins. """ # ------------------------------------------------------------------------- # Initialization # ------------------------------------------------------------------------- + def pytest_addhooks(pluginmanager): """called at plugin load time to allow adding new hooks via a call to pluginmanager.registerhooks(module).""" @@ -15,13 +17,16 @@ are parsed. """ + def pytest_cmdline_parse(pluginmanager, args): """return initialized config object, parsing the specified args. """ pytest_cmdline_parse.firstresult = True + def pytest_cmdline_preparse(config, args): """(deprecated) modify command line arguments before option parsing. """ + def pytest_addoption(parser): """register argparse-style options and ini-style config values. @@ -42,28 +47,34 @@ - :py:func:`config.getini(name) <_pytest.config.Config.getini>` to retrieve a value read from an ini-style file. - The config object is passed around on many internal objects via the ``.config`` - attribute or can be retrieved as the ``pytestconfig`` fixture or accessed - via (deprecated) ``pytest.config``. + The config object is passed around on many internal objects + via the ``.config`` attribute or can be retrieved as + the ``pytestconfig`` fixture or + accessed via (deprecated) ``pytest.config``. """ + def pytest_cmdline_main(config): """ called for performing the main command line action. The default implementation will invoke the configure hooks and runtest_mainloop. """ pytest_cmdline_main.firstresult = True + def pytest_load_initial_conftests(args, early_config, parser): """ implements the loading of initial conftest files ahead of command line option parsing. """ + def pytest_configure(config): """ called after command line options have been parsed and all plugins and initial conftest files been loaded. """ + def pytest_unconfigure(config): """ called before test process is exited. """ + def pytest_runtestloop(session): """ called for performing the main runtest loop (after collection finished). """ @@ -73,17 +84,21 @@ # collection hooks # ------------------------------------------------------------------------- + def pytest_collection(session): """ perform the collection protocol for the given session. """ pytest_collection.firstresult = True + def pytest_collection_modifyitems(session, config, items): """ called after collection has been performed, may filter or re-order the items in-place.""" + def pytest_collection_finish(session): """ called after collection has been performed and modified. """ + def pytest_ignore_collect(path, config): """ return True to prevent considering this path for collection. This hook is consulted for all files and directories prior to calling @@ -91,31 +106,39 @@ """ pytest_ignore_collect.firstresult = True + def pytest_collect_directory(path, parent): """ called before traversing a directory for collection files. """ pytest_collect_directory.firstresult = True + def pytest_collect_file(path, parent): """ return collection Node or None for the given path. Any new node needs to have the specified ``parent`` as a parent.""" + # logging hooks for collection def pytest_collectstart(collector): """ collector starts collecting. """ + def pytest_itemcollected(item): """ we just collected a test item. """ + def pytest_collectreport(report): """ collector finished collecting. """ + def pytest_deselected(items): """ called for test items deselected by keyword. """ + def pytest_make_collect_report(collector): """ perform ``collector.collect()`` and return a CollectReport. """ pytest_make_collect_report.firstresult = True + # ------------------------------------------------------------------------- # Python test function related hooks # ------------------------------------------------------------------------- @@ -128,23 +151,29 @@ """ pytest_pycollect_makemodule.firstresult = True + def pytest_pycollect_makeitem(collector, name, obj): - """ return custom item/collector for a python object in a module, or None. """ + """ return custom item/collector + for a python object in a module, or None. """ pytest_pycollect_makeitem.firstresult = True + def pytest_pyfunc_call(pyfuncitem): """ call underlying test function. """ pytest_pyfunc_call.firstresult = True + def pytest_generate_tests(metafunc): """ generate (multiple) parametrized calls to a test function.""" + # ------------------------------------------------------------------------- # generic runtest related hooks # ------------------------------------------------------------------------- def pytest_itemstart(item, node): """ (deprecated, use pytest_runtest_logstart). """ + def pytest_runtest_protocol(item, nextitem): """ implements the runtest_setup/call/teardown protocol for the given test item, including capturing exceptions and calling @@ -160,15 +189,19 @@ """ pytest_runtest_protocol.firstresult = True + def pytest_runtest_logstart(nodeid, location): """ signal the start of running a single test item. """ + def pytest_runtest_setup(item): """ called before ``pytest_runtest_call(item)``. """ + def pytest_runtest_call(item): """ called to execute the test ``item``. """ + def pytest_runtest_teardown(item, nextitem): """ called after ``pytest_runtest_call``. @@ -178,6 +211,7 @@ so that nextitem only needs to call setup-functions. """ + def pytest_runtest_makereport(item, call): """ return a :py:class:`_pytest.runner.TestReport` object for the given :py:class:`pytest.Item` and @@ -185,6 +219,7 @@ """ pytest_runtest_makereport.firstresult = True + def pytest_runtest_logreport(report): """ process a test setup/call/teardown report relating to the respective phase of executing a test. """ @@ -193,9 +228,11 @@ # test session related hooks # ------------------------------------------------------------------------- + def pytest_sessionstart(session): """ before session.main() is called. """ + def pytest_sessionfinish(session, exitstatus): """ whole test run finishes. """ @@ -217,16 +254,21 @@ # hooks for influencing reporting (invoked from _pytest_terminal) # ------------------------------------------------------------------------- + def pytest_report_header(config, startdir): - """ return a string to be displayed as header info for terminal reporting.""" + """ return a string to be displayed + as header info for terminal reporting.""" + def pytest_report_teststatus(report): """ return result-category, shortletter and verbose word for reporting.""" pytest_report_teststatus.firstresult = True + def pytest_terminal_summary(terminalreporter): """ add additional section in terminal summary reporting. """ + def pytest_logwarning(message, code, nodeid, fslocation): """ process a warning specified by a message, a code string, a nodeid and fslocation (both of which may be None @@ -236,6 +278,7 @@ # doctest hooks # ------------------------------------------------------------------------- + def pytest_doctest_prepare_content(content): """ return processed content for a given doctest""" pytest_doctest_prepare_content.firstresult = True @@ -244,15 +287,19 @@ # error handling and internal debugging hooks # ------------------------------------------------------------------------- + def pytest_plugin_registered(plugin, manager): """ a new pytest plugin got registered. """ + def pytest_internalerror(excrepr, excinfo): """ called for internal errors. """ + def pytest_keyboard_interrupt(excinfo): """ called for keyboard interrupt. """ + def pytest_exception_interact(node, call, report): """ (experimental, new in 2.4) called when an exception was raised which can potentially be @@ -262,5 +309,6 @@ that is not an internal exception like "skip.Exception". """ + def pytest_enter_pdb(): """ called upon pdb.set_trace()""" diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/junitxml.py --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -1,4 +1,5 @@ -""" report test results in JUnit-XML format, for use with Hudson and build integration servers. +""" report test results in JUnit-XML format, +for use with Hudson and build integration servers. Based on initial code from Ross Lawley. """ @@ -16,6 +17,7 @@ unicode = str long = int + class Junit(py.xml.Namespace): pass @@ -32,9 +34,10 @@ (0xE000, 0xFFFD), (0x10000, 0x10FFFF), ) -_legal_xml_re = [unicode("%s-%s") % (unichr(low), unichr(high)) - for (low, high) in _legal_ranges - if low < sys.maxunicode] +_legal_xml_re = [ + unicode("%s-%s") % (unichr(low), unichr(high)) + for (low, high) in _legal_ranges + if low < sys.maxunicode] _legal_xml_re = [unichr(x) for x in _legal_chars] + _legal_xml_re illegal_xml_re = re.compile(unicode('[^%s]') % unicode('').join(_legal_xml_re)) @@ -42,6 +45,7 @@ del _legal_ranges del _legal_xml_re + def bin_xml_escape(arg): def repl(matchobj): i = ord(matchobj.group()) @@ -51,14 +55,18 @@ return unicode('#x%04X') % i return py.xml.raw(illegal_xml_re.sub(repl, py.xml.escape(arg))) + def pytest_addoption(parser): group = parser.getgroup("terminal reporting") - group.addoption('--junitxml', '--junit-xml', action="store", - dest="xmlpath", metavar="path", default=None, - help="create junit-xml style report file at given path.") - group.addoption('--junitprefix', '--junit-prefix', action="store", - metavar="str", default=None, - help="prepend prefix to classnames in junit-xml output") + group.addoption( + '--junitxml', '--junit-xml', action="store", + dest="xmlpath", metavar="path", default=None, + help="create junit-xml style report file at given path.") + group.addoption( + '--junitprefix', '--junit-prefix', action="store", + metavar="str", default=None, + help="prepend prefix to classnames in junit-xml output") + def pytest_configure(config): xmlpath = config.option.xmlpath @@ -67,6 +75,7 @@ config._xml = LogXML(xmlpath, config.option.junitprefix) config.pluginmanager.register(config._xml) + def pytest_unconfigure(config): xml = getattr(config, '_xml', None) if xml: @@ -79,6 +88,7 @@ names[0] = names[0].replace("/", '.') return names + class LogXML(object): def __init__(self, logfile, prefix): logfile = os.path.expanduser(os.path.expandvars(logfile)) @@ -102,11 +112,11 @@ def _write_captured_output(self, report): for capname in ('out', 'err'): allcontent = "" - for name, content in report.get_sections("Captured std%s" % - capname): + for name, content in report.get_sections( + "Captured std%s" % capname): allcontent += content if allcontent: - tag = getattr(Junit, 'system-'+capname) + tag = getattr(Junit, 'system-' + capname) self.append(tag(bin_xml_escape(allcontent))) def append(self, obj): @@ -117,7 +127,7 @@ self._write_captured_output(report) def append_failure(self, report): - #msg = str(report.longrepr.reprtraceback.extraline) + # msg = str(report.longrepr.reprtraceback.extraline) if hasattr(report, "wasxfail"): self.append( Junit.skipped(message="xfail-marked test passes unexpectedly")) @@ -130,13 +140,13 @@ self._write_captured_output(report) def append_collect_error(self, report): - #msg = str(report.longrepr.reprtraceback.extraline) + # msg = str(report.longrepr.reprtraceback.extraline) self.append(Junit.error(bin_xml_escape(report.longrepr), message="collection failure")) self.errors += 1 def append_collect_skipped(self, report): - #msg = str(report.longrepr.reprtraceback.extraline) + # msg = str(report.longrepr.reprtraceback.extraline) self.append(Junit.skipped(bin_xml_escape(report.longrepr), message="collection skipped")) self.skipped += 1 @@ -154,17 +164,16 @@ filename, lineno, skipreason = report.longrepr if skipreason.startswith("Skipped: "): skipreason = bin_xml_escape(skipreason[9:]) - self.append( - Junit.skipped("%s:%s: %s" % (filename, lineno, skipreason), - type="pytest.skip", - message=skipreason - )) + self.append(Junit.skipped( + "%s:%s: %s" % (filename, lineno, skipreason), + type="pytest.skip", message=skipreason, + )) self.skipped += 1 self._write_captured_output(report) def pytest_runtest_logreport(self, report): if report.passed: - if report.when == "call": # ignore setup/teardown + if report.when == "call": # ignore setup/teardown self._opentestcase(report) self.append_pass(report) elif report.failed: @@ -190,9 +199,9 @@ data = bin_xml_escape(excrepr) self.tests.append( Junit.testcase( - Junit.error(data, message="internal error"), - classname="pytest", - name="internal")) + Junit.error(data, message="internal error"), + classname="pytest", + name="internal")) def pytest_sessionstart(self): self.suite_start_time = time.time() @@ -216,4 +225,5 @@ logfile.close() def pytest_terminal_summary(self, terminalreporter): - terminalreporter.write_sep("-", "generated xml file: %s" % (self.logfile)) + terminalreporter.write_sep( + "-", "generated xml file: %s" % (self.logfile)) diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -2,8 +2,11 @@ import re import py -import pytest, _pytest -import os, sys, imp +import pytest +import _pytest +import os +import sys +import imp try: from collections import MutableMapping as MappingMixin except ImportError: @@ -22,54 +25,69 @@ name_re = re.compile("^[a-zA-Z_]\w*$") + def pytest_addoption(parser): - parser.addini("norecursedirs", "directory patterns to avoid for recursion", + parser.addini( + "norecursedirs", "directory patterns to avoid for recursion", type="args", default=['.*', 'CVS', '_darcs', '{arch}', '*.egg']) - #parser.addini("dirpatterns", + # parser.addini("dirpatterns", # "patterns specifying possible locations of test files", # type="linelist", default=["**/test_*.txt", # "**/test_*.py", "**/*_test.py"] - #) + # ) group = parser.getgroup("general", "running and selection options") - group._addoption('-x', '--exitfirst', action="store_true", default=False, - dest="exitfirst", - help="exit instantly on first error or failed test."), - group._addoption('--maxfail', metavar="num", - action="store", type=int, dest="maxfail", default=0, - help="exit after first num failures or errors.") - group._addoption('--strict', action="store_true", - help="run pytest in strict mode, warnings become errors.") - group._addoption("-c", metavar="file", type=str, dest="inifilename", - help="load configuration from `file` instead of trying to locate one of the implicit configuration files.") + group._addoption( + '-x', '--exitfirst', action="store_true", default=False, + dest="exitfirst", + help="exit instantly on first error or failed test."), + group._addoption( + '--maxfail', metavar="num", + action="store", type=int, dest="maxfail", default=0, + help="exit after first num failures or errors.") + group._addoption( + '--strict', action="store_true", + help="run pytest in strict mode, warnings become errors.") + group._addoption( + "-c", metavar="file", type=str, dest="inifilename", + help="load configuration from `file` instead of " + "trying to locate one of the implicit configuration files.") group = parser.getgroup("collect", "collection") - group.addoption('--collectonly', '--collect-only', action="store_true", + group.addoption( + '--collectonly', '--collect-only', action="store_true", help="only collect tests, don't execute them."), - group.addoption('--pyargs', action="store_true", + group.addoption( + '--pyargs', action="store_true", help="try to interpret all arguments as python packages.") - group.addoption("--ignore", action="append", metavar="path", + group.addoption( + "--ignore", action="append", metavar="path", help="ignore path during collection (multi-allowed).") # when changing this to --conf-cut-dir, config.py Conftest.setinitial # needs upgrading as well - group.addoption('--confcutdir', dest="confcutdir", default=None, + group.addoption( + '--confcutdir', dest="confcutdir", default=None, metavar="dir", help="only load conftest.py's relative to specified dir.") - group = parser.getgroup("debugconfig", + group = parser.getgroup( + "debugconfig", "test session debugging and configuration") - group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir", - help="base temporary directory for this test run.") + group.addoption( + '--basetemp', dest="basetemp", default=None, metavar="dir", + help="base temporary directory for this test run.") def pytest_namespace(): collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) return dict(collect=collect) + def pytest_configure(config): - pytest.config = config # compatibiltiy + pytest.config = config # compatibiltiy if config.option.exitfirst: config.option.maxfail = 1 + def wrap_session(config, doit): """Skeleton command line program""" session = Session(config) @@ -85,7 +103,7 @@ except pytest.UsageError: args = sys.exc_info()[1].args for msg in args: - sys.stderr.write("ERROR: %s\n" %(msg,)) + sys.stderr.write("ERROR: %s\n" % (msg,)) session.exitstatus = EXIT_USAGEERROR except KeyboardInterrupt: excinfo = py.code.ExceptionInfo() @@ -112,18 +130,22 @@ config.pluginmanager.ensure_shutdown() return session.exitstatus + def pytest_cmdline_main(config): return wrap_session(config, _main) + def _main(config, session): """ default command line protocol for initialization, session, running tests and reporting. """ config.hook.pytest_collection(session=session) config.hook.pytest_runtestloop(session=session) + def pytest_collection(session): return session.perform_collect() + def pytest_runtestloop(session): if session.config.option.collectonly: return True @@ -133,7 +155,7 @@ # keeping sys.exc_info set when calling into a test # python2 keeps sys.exc_info till the frame is left try: - return session.items[i+1] + return session.items[i + 1] except IndexError: return None @@ -144,6 +166,7 @@ raise session.Interrupted(session.shouldstop) return True + def pytest_ignore_collect(path, config): p = path.dirpath() ignore_paths = config._getconftest_pathlist("collect_ignore", path=p) @@ -153,6 +176,7 @@ ignore_paths.extend([py.path.local(x) for x in excludeopt]) return path in ignore_paths + class FSHookProxy(object): def __init__(self, fspath, config): self.fspath = fspath @@ -172,6 +196,7 @@ return property(fget) + class NodeKeywords(MappingMixin): def __init__(self, node): self.node = node @@ -237,14 +262,14 @@ # used for storing artificial fixturedefs for direct parametrization self._name2pseudofixturedef = {} - #self.extrainit() + # self.extrainit() @property def ihook(self): """ fspath sensitive hook proxy used to call pytest hooks""" return self.session.gethookproxy(self.fspath) - #def extrainit(self): + # def extrainit(self): # """"extra initialization after Node is initialized. Implemented # by some subclasses. """ @@ -258,14 +283,15 @@ def _getcustomclass(self, name): cls = getattr(self, name) if cls != getattr(pytest, name): - py.log._apiwarn("2.0", "use of node.%s is deprecated, " + py.log._apiwarn( + "2.0", "use of node.%s is deprecated, " "use pytest_pycollect_makeitem(...) to create custom " "collection nodes" % name) return cls def __repr__(self): - return "<%s %r>" %(self.__class__.__name__, - getattr(self, 'name', None)) + return "<%s %r>" % (self.__class__.__name__, + getattr(self, 'name', None)) def warn(self, code, message): """ generate a warning with the given code and message for this @@ -392,13 +418,14 @@ return excinfo.value.formatrepr() tbfilter = True if self.config.option.fulltrace: - style="long" + style = "long" else: self._prunetraceback(excinfo) tbfilter = False # prunetraceback already does it if style == "auto": style = "long" - # XXX should excinfo.getrepr record all data and toterminal() process it? + # XXX should excinfo.getrepr record all data + # and toterminal() process it? if style is None: if self.config.option.tbstyle == "short": style = "short" @@ -411,6 +438,7 @@ repr_failure = _repr_failure_py + class Collector(Node): """ Collector instances create children through collect() and thus iteratively build a tree. @@ -444,9 +472,10 @@ ntraceback = ntraceback.cut(excludepath=tracebackcutdir) excinfo.traceback = ntraceback.filter() + class FSCollector(Collector): def __init__(self, fspath, parent=None, config=None, session=None): - fspath = py.path.local(fspath) # xxx only for test_resultlog.py? + fspath = py.path.local(fspath) # xxx only for test_resultlog.py? name = fspath.basename if parent is not None: rel = fspath.relto(parent.fspath) @@ -464,9 +493,11 @@ relpath = relpath.replace(os.sep, "/") return relpath + class File(FSCollector): """ base class for collecting tests from a file. """ + class Item(Node): """ a basic test invocation item. Note that for a single function there might be multiple test invocation items. @@ -501,13 +532,15 @@ self._location = location return location + class NoMatch(Exception): """ raised if matching cannot locate a matching names. """ + class Session(FSCollector): class Interrupted(KeyboardInterrupt): """ signals an interrupted test run. """ - __module__ = 'builtins' # for py3 + __module__ = 'builtins' # for py3 def __init__(self, config): FSCollector.__init__(self, py.path.local(), parent=None, @@ -547,8 +580,8 @@ hook = self.config.hook try: items = self._perform_collect(args, genitems) - hook.pytest_collection_modifyitems(session=self, - config=self.config, items=items) + hook.pytest_collection_modifyitems( + session=self, config=self.config, items=items) finally: hook.pytest_collection_finish(session=self) return items @@ -574,7 +607,7 @@ for arg, exc in self._notfound: line = "(no name %r in any of %r)" % (arg, exc.args[0]) errors.append("not found: %s\n%s" % (arg, line)) - #XXX: test this + # XXX: test this raise pytest.UsageError(*errors) if not genitems: return rep.result @@ -603,7 +636,7 @@ names = self._parsearg(arg) path = names.pop(0) if path.check(dir=1): - assert not names, "invalid arg %r" %(arg,) + assert not names, "invalid arg %r" % (arg,) for path in path.visit(fil=lambda x: x.check(file=1), rec=self._recurse, bf=True, sort=True): for x in self._collectfile(path): @@ -724,5 +757,3 @@ for x in self.genitems(subnode): yield x node.ihook.pytest_collectreport(report=rep) - - diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -192,10 +192,12 @@ if name not in self._markers: raise AttributeError("%r not a registered marker" % (name,)) + def istestfunc(func): return hasattr(func, "__call__") and \ getattr(func, "__name__", "<lambda>") != "<lambda>" + class MarkDecorator: """ A decorator for test functions and test classes. When applied it will create :class:`MarkInfo` objects which may be @@ -236,7 +238,8 @@ @property def markname(self): - return self.name # for backward-compat (2.4.1 had this attr) + # for backward-compat (2.4.1 had this attr) + return self.name def __repr__(self): d = self.__dict__.copy() diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/monkeypatch.py --- a/_pytest/monkeypatch.py +++ b/_pytest/monkeypatch.py @@ -1,8 +1,10 @@ """ monkeypatching and mocking functionality. """ -import os, sys +import os +import sys from py.builtin import _basestring + def pytest_funcarg__monkeypatch(request): """The returned ``monkeypatch`` funcarg provides these helper methods to modify objects, dictionaries or os.environ:: @@ -26,7 +28,6 @@ return mpatch - def derive_importpath(import_path): import pytest if not isinstance(import_path, _basestring) or "." not in import_path: @@ -58,13 +59,13 @@ return attr, obj - class Notset: def __repr__(self): return "<notset>" notset = Notset() + class monkeypatch: """ Object keeping a record of setattr/item/env/syspath changes. """ def __init__(self): @@ -91,15 +92,16 @@ if value is notset: if not isinstance(target, _basestring): - raise TypeError("use setattr(target, name, value) or " - "setattr(target, value) with target being a dotted " - "import string") + raise TypeError( + "use setattr(target, name, value) or " + "setattr(target, value) with target being a dotted " + "import string") value = name name, target = derive_importpath(target) oldval = getattr(target, name, notset) if raising and oldval is notset: - raise AttributeError("%r has no attribute %r" %(target, name)) + raise AttributeError("%r has no attribute %r" % (target, name)) # avoid class descriptors like staticmethod/classmethod if inspect.isclass(target): @@ -202,7 +204,8 @@ try: del dictionary[name] except KeyError: - pass # was already deleted, so we have the desired state + # was already deleted, so we have the desired state + pass else: dictionary[name] = value self._setitem[:] = [] diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/nose.py --- a/_pytest/nose.py +++ b/_pytest/nose.py @@ -19,8 +19,8 @@ def pytest_runtest_makereport(item, call): if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()): # let's substitute the excinfo with a pytest.skip one - call2 = call.__class__(lambda: - pytest.skip(str(call.excinfo.value)), call.when) + call2 = call.__class__( + lambda: pytest.skip(str(call.excinfo.value)), call.when) call.excinfo = call2.excinfo @@ -37,14 +37,16 @@ if not call_optional(item.obj, 'setup'): # call module level setup if there is no object level one call_optional(item.parent.obj, 'setup') - #XXX this implies we only call teardown when setup worked - item.session._setupstate.addfinalizer((lambda: teardown_nose(item)), item) + # XXX this implies we only call teardown when setup worked + item.session._setupstate.addfinalizer( + (lambda: teardown_nose(item)), item) + def teardown_nose(item): if is_potential_nosetest(item): if not call_optional(item.obj, 'teardown'): call_optional(item.parent.obj, 'teardown') - #if hasattr(item.parent, '_nosegensetup'): + # if hasattr(item.parent, '_nosegensetup'): # #call_optional(item._nosegensetup, 'teardown') # del item.parent._nosegensetup diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/pastebin.py --- a/_pytest/pastebin.py +++ b/_pytest/pastebin.py @@ -1,16 +1,19 @@ """ submit failure or test session information to a pastebin service. """ import pytest -import py, sys +import py +import sys import tempfile def pytest_addoption(parser): group = parser.getgroup("terminal reporting") - group._addoption('--pastebin', metavar="mode", + group._addoption( + '--pastebin', metavar="mode", action='store', dest="pastebin", default=None, choices=['failed', 'all'], help="send failed|all info to bpaste.net pastebin service.") + @pytest.mark.trylast def pytest_configure(config): if config.option.pastebin == "all": @@ -21,11 +24,13 @@ if tr is not None: config._pastebinfile = tempfile.TemporaryFile('w+') oldwrite = tr._tw.write + def tee_write(s, **kwargs): oldwrite(s, **kwargs) config._pastebinfile.write(str(s)) tr._tw.write = tee_write + def pytest_unconfigure(config): if hasattr(config, '_pastebinfile'): # get terminal contents and delete file @@ -41,6 +46,7 @@ pastebinurl = create_new_paste(sessionlog) tr.write_line("pastebin session-log: %s\n" % pastebinurl) + def create_new_paste(contents): """ Creates a new paste using bpaste.net service. @@ -68,6 +74,7 @@ else: return 'bad response: ' + response + def pytest_terminal_summary(terminalreporter): if terminalreporter.config.option.pastebin != "failed": return @@ -84,4 +91,4 @@ s = tw.stringio.getvalue() assert len(s) pastebinurl = create_new_paste(s) - tr.write_line("%s --> %s" %(msg, pastebinurl)) + tr.write_line("%s --> %s" % (msg, pastebinurl)) diff -r 702eec88814bac62c7a852f0b0ba3fac6cb5e98e -r c5689ba15d60a456526d8f4223bd575f6fc32046 _pytest/pdb.py --- a/_pytest/pdb.py +++ b/_pytest/pdb.py @@ -9,24 +9,28 @@ def pytest_addoption(parser): group = parser.getgroup("general") - group._addoption('--pdb', - action="store_true", dest="usepdb", default=False, - help="start the interactive Python debugger on errors.") + group._addoption( + '--pdb', action="store_true", dest="usepdb", default=False, + help="start the interactive Python debugger on errors.") + def pytest_namespace(): return {'set_trace': pytestPDB().set_trace} + def pytest_configure(config): if config.getvalue("usepdb"): config.pluginmanager.register(PdbInvoke(), 'pdbinvoke') old = (pdb.set_trace, pytestPDB._pluginmanager) + def fin(): pdb.set_trace, pytestPDB._pluginmanager = old pdb.set_trace = pytest.set_trace pytestPDB._pluginmanager = config.pluginmanager config._cleanup.append(fin) + class pytestPDB: """ Pseudo PDB that defers to the real pdb. """ _pluginmanager = None @@ -55,7 +59,7 @@ def pytest_internalerror(self, excrepr, excinfo): for line in str(excrepr).split("\n"): - sys.stderr.write("INTERNALERROR> %s\n" %line) + sys.stderr.write("INTERNALERROR> %s\n" % line) sys.stderr.flush() tb = _postmortem_traceback(excinfo) post_mortem(tb) This diff is so big that we needed to truncate the remainder. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. _______________________________________________ pytest-commit mailing list pytest-commit@python.org https://mail.python.org/mailman/listinfo/pytest-commit