diff --git a/CHANGELOG b/CHANGELOG index 10a553ac1..8f3b58cf0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,8 @@ Changes between 1.3.2 and 1.3.3a1 - fix weirdness: make terminal width detection work on stdout instead of stdin (thanks Armin Ronacher for reporting) +- remove trailing whitespace in all py/text files + Changes between 1.3.1 and 1.3.2 ================================================== diff --git a/ISSUES.txt b/ISSUES.txt index c0ca4399a..f585b00f1 100644 --- a/ISSUES.txt +++ b/ISSUES.txt @@ -1,78 +1,78 @@ -refine session initialization / fix custom collect crash +refine session initialization / fix custom collect crash --------------------------------------------------------------- -tags: bug 1.4 core xdist +tags: bug 1.4 core xdist -When calling "py.test path/X" py.test can crash if the collection +When calling "py.test path/X" py.test can crash if the collection of that directory is skipped. Calling "py.test path" will give -proper output. The reason is that for the very first colitems -getinitialnodes() and a collection is done before the fully -controlled session and pytest_make_collect_report protocol takes over. +proper output. The reason is that for the very first colitems +getinitialnodes() and a collection is done before the fully +controlled session and pytest_make_collect_report protocol takes over. Try to remove the redundant getinitialnodes related logic and amend -the session collect logic to care for this "initial" case as well. +the session collect logic to care for this "initial" case as well. Apart from simplification a side effect the dsession's session -and the core session probably converge some more. +and the core session probably converge some more. -do early-teardown of test modules +do early-teardown of test modules ----------------------------------------- tags: feature 1.3 currently teardowns are called when the next tests is setup -except for the function/method level where interally +except for the function/method level where interally "teardown_exact" tears down immediately. Generalize this to perform the "neccessary" teardown compared to the "next" test item during teardown - this should -get rid of some irritations because otherwise e.g. -prints of teardown-code appear in the setup of the next test. +get rid of some irritations because otherwise e.g. +prints of teardown-code appear in the setup of the next test. consider and document __init__ file usage in test directories --------------------------------------------------------------- -tags: bug 1.4 core +tags: bug 1.4 core Currently, a test module is imported with its fully qualified -package path, determined by checking __init__ files upwards. -This has the side effect that a source package at the root +package path, determined by checking __init__ files upwards. +This has the side effect that a source package at the root of the test dir could be imported as well. This is somewhat convenient but complicates the picture for running tests against -different versions of a package. Also, implicit sys.path +different versions of a package. Also, implicit sys.path manipulations are problematic per-se. Maybe factorting out a pytest_addsyspath hook which can be disabled from the command line -makes sense. In any case documentation/recommendations for -certain scenarios makes sense. +makes sense. In any case documentation/recommendations for +certain scenarios makes sense. relax requirement to have tests/testing contain an __init__ ---------------------------------------------------------------- tags: feature 1.4 bb: http://bitbucket.org/hpk42/py-trunk/issue/64 -A local test run of a "tests" directory may work +A local test run of a "tests" directory may work but a remote one fail because the tests directory does not contain an "__init__.py". Either give an error or make it work without the __init__.py -i.e. port the nose-logic of unloading a test module. +i.e. port the nose-logic of unloading a test module. -customize test function collection +customize test function collection ------------------------------------------------------- tags: feature 1.4 - introduce py.test.mark.nocollect for not considering a function for test collection at all. maybe also introduce a py.test.mark.test to explicitely mark a function to become a tested one. Lookup JUnit ways - of tagging tests. + of tagging tests. - allow an easy way to customize "test_", "Test" prefixes for file paths and test function/class names. the current customizable Item requires - too much code/concepts to influence this collection matching. + too much code/concepts to influence this collection matching. maybe introduce pytest_pycollect_filters = { - 'file': 'test*.py', - 'function': 'test*', - 'class': 'Test*', + 'file': 'test*.py', + 'function': 'test*', + 'class': 'Test*', } -introduce py.test.mark.platform +introduce py.test.mark.platform ------------------------------------------------------- tags: feature 1.4 -Introduce nice-to-spell platform-skipping, examples: +Introduce nice-to-spell platform-skipping, examples: @py.test.mark.platform("python3") @py.test.mark.platform("not python3") @@ -82,8 +82,8 @@ Introduce nice-to-spell platform-skipping, examples: @py.test.mark.platform("not (jython and win32)", xfail=True) etc. Idea is to allow Python expressions which can operate -on common spellings for operating systems and python -interpreter versions. +on common spellings for operating systems and python +interpreter versions. introduce py.test.mark registration ----------------------------------------- @@ -92,73 +92,73 @@ tags: feature 1.4 introduce a hook that allows to register a named mark decorator with documentation and add "py.test --marks" to get a list of available marks. Deprecate "dynamic" mark -definitions. +definitions. -allow to non-intrusively apply skipfs/xfail/marks +allow to non-intrusively apply skipfs/xfail/marks --------------------------------------------------- tags: feature 1.4 -use case: mark a module or directory structures -to be skipped on certain platforms (i.e. no import -attempt will be made). +use case: mark a module or directory structures +to be skipped on certain platforms (i.e. no import +attempt will be made). -consider introducing a hook/mechanism that allows to apply marks -from conftests or plugins. +consider introducing a hook/mechanism that allows to apply marks +from conftests or plugins. -explicit referencing of conftest.py files +explicit referencing of conftest.py files ----------------------------------------- tags: feature 1.4 -allow to name conftest.py files (in sub directories) that should -be imported early, as to include command line options. +allow to name conftest.py files (in sub directories) that should +be imported early, as to include command line options. -a central py.test ini/yml file +a central py.test ini/yml file ---------------------------------- tags: feature 1.4 introduce a declarative configuration file that allows: -- default options -- to-be-collected test directories +- default options +- to-be-collected test directories - required plugins -- test func/class/file matching patterns -- skip/xfail (non-intrusive) -- pytest.ini and tox.ini and setup.cfg configuration in the same file +- test func/class/file matching patterns +- skip/xfail (non-intrusive) +- pytest.ini and tox.ini and setup.cfg configuration in the same file -new documentation +new documentation ---------------------------------- tags: feature 1.4 -- logo py.test -- reference / customization +- logo py.test +- reference / customization - writing a (local or global) plugin -- examples for unittest or functional testing -- resource management for functional testing -- patterns: page object -- parametrized testing -- better / more integrated plugin docs +- examples for unittest or functional testing +- resource management for functional testing +- patterns: page object +- parametrized testing +- better / more integrated plugin docs i.e. not per-plugin but per-feature referencing a plugin generalize parametrized testing to generate combinations ------------------------------------------------------------- -tags: feature 1.4 +tags: feature 1.4 think about extending metafunc.addcall or add a new method to allow to generate tests with combinations of all generated versions - what to do -about "id" and "param" in such combinations though? +about "id" and "param" in such combinations though? -introduce py.test.mark.multi +introduce py.test.mark.multi ----------------------------------------- tags: feature 1.3 introduce py.test.mark.multi to specify a number -of values for a given function argument. +of values for a given function argument. have imported module mismatch honour relative paths -------------------------------------------------------- tags: bug 1.4 -With 1.1.1 py.test fails at least on windows if an import -is relative and compared against an absolute conftest.py +With 1.1.1 py.test fails at least on windows if an import +is relative and compared against an absolute conftest.py path. Normalize. make node._checkcollectable more robust @@ -167,8 +167,8 @@ tags: bug 1.4 currently node._checkcollectable() can raise exceptions for all kinds of reasons ('conftest.py' loading -problems, missing rsync-dirs, platform-skip-at-import-level -issues, ...). It should just return True/False and cause +problems, missing rsync-dirs, platform-skip-at-import-level +issues, ...). It should just return True/False and cause a good error message. call termination with small timeout @@ -176,15 +176,15 @@ call termination with small timeout tags: feature 1.4 test: testing/pytest/dist/test_dsession.py - test_terminate_on_hanging_node -Call gateway group termination with a small timeout if available. +Call gateway group termination with a small timeout if available. Should make dist-testing less likely to leave lost processes. -consider globals: py.test.ensuretemp and config +consider globals: py.test.ensuretemp and config -------------------------------------------------------------- tags: experimental-wish 1.4 -consider deprecating py.test.ensuretemp and py.test.config -to further reduce py.test globality. Also consider +consider deprecating py.test.ensuretemp and py.test.config +to further reduce py.test globality. Also consider having py.test.config and ensuretemp coming from a plugin rather than being there from the start. @@ -192,16 +192,16 @@ consider allowing funcargs for setup methods -------------------------------------------------------------- tags: experimental-wish 1.4 -Users have expressed the wish to have funcargs available to setup +Users have expressed the wish to have funcargs available to setup functions. Experiment with allowing funcargs there - it might also help to make the py.test.ensuretemp and config deprecation. -For filling funcargs for setup methods, we could call funcarg -factories with a request object that not have a cls/function +For filling funcargs for setup methods, we could call funcarg +factories with a request object that not have a cls/function attributes. However, how to handle parametrized test functions -and funcargs? +and funcargs? setup_function -> request can be like it is now -setup_class -> request has no request.function +setup_class -> request has no request.function setup_module -> request has no request.cls consider pytest_addsyspath hook @@ -210,31 +210,31 @@ tags: 1.4 py.test could call a new pytest_addsyspath() in order to systematically allow manipulation of sys.path and to inhibit it via --no-addsyspath -in order to more easily run against installed packages. +in order to more easily run against installed packages. -Alternatively it could also be done via the config object -and pytest_configure. +Alternatively it could also be done via the config object +and pytest_configure. -show plugin information in test header +show plugin information in test header ---------------------------------------------------------------- tags: feature 1.4 -Now that external plugins are becoming more numerous +Now that external plugins are becoming more numerous it would be useful to have external plugins along with -their versions displayed as a header line. +their versions displayed as a header line. -deprecate global py.test.config usage +deprecate global py.test.config usage ---------------------------------------------------------------- tags: feature 1.4 -py.test.ensuretemp and py.test.config are probably the last -objects containing global state. Often using them is not -neccessary. This is about trying to get rid of them, i.e. -deprecating them and checking with PyPy's usages as well -as others. +py.test.ensuretemp and py.test.config are probably the last +objects containing global state. Often using them is not +neccessary. This is about trying to get rid of them, i.e. +deprecating them and checking with PyPy's usages as well +as others. -remove deprecated bits in collect.py +remove deprecated bits in collect.py ------------------------------------------------------------------- tags: feature 1.4 diff --git a/README.txt b/README.txt index 8280ba320..63a0d5557 100644 --- a/README.txt +++ b/README.txt @@ -1,8 +1,8 @@ -The py lib is a Python development support library featuring +The py lib is a Python development support library featuring the following tools and modules: * py.test: tool for distributed automated testing * py.code: dynamic code generation and introspection -* py.path: uniform local and svn path objects +* py.path: uniform local and svn path objects For questions and more information please visit http://pylib.org diff --git a/bin-for-dist/findmissingdocstrings.py b/bin-for-dist/findmissingdocstrings.py index dd77534c5..c354de61e 100755 --- a/bin-for-dist/findmissingdocstrings.py +++ b/bin-for-dist/findmissingdocstrings.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python import py import inspect @@ -73,4 +73,4 @@ if __name__ == '__main__': for name, obj in all_exported: if isinstance(obj, type): report_different_parameter_names(name, obj) - + diff --git a/bin-for-dist/hudson.py b/bin-for-dist/hudson.py index f524a6a4c..ba526ffe6 100644 --- a/bin-for-dist/hudson.py +++ b/bin-for-dist/hudson.py @@ -16,11 +16,11 @@ BIN=os.path.abspath(os.path.join(BUILDNAME, 'bin')) if not os.path.exists(BIN): BIN=os.path.abspath(os.path.join(BUILDNAME, 'Scripts')) assert os.path.exists(BIN) - + PYTHON=os.path.join(BIN, 'python') bincall("python", "setup.py", "develop", "-q") -bincall("pip", "install", "-r", "testing/pip-reqs1.txt", +bincall("pip", "install", "-r", "testing/pip-reqs1.txt", "-q", "--download-cache=download") -bincall("py.test", "--ignore", BUILDNAME, - "--xml=junit.xml", +bincall("py.test", "--ignore", BUILDNAME, + "--xml=junit.xml", "--report=skipped", "--runslowtest", *sys.argv[1:]) diff --git a/bin-for-dist/makepluginlist.py b/bin-for-dist/makepluginlist.py index 698c69193..f94f54892 100644 --- a/bin-for-dist/makepluginlist.py +++ b/bin-for-dist/makepluginlist.py @@ -3,30 +3,30 @@ import os, sys WIDTH = 75 plugins = [ - ('advanced python testing', + ('advanced python testing', 'skipping mark pdb figleaf ' 'monkeypatch coverage cov capture capturelog recwarn tmpdir',), ('distributed testing, CI and deployment', 'xdist pastebin junitxml resultlog genscript',), ('testing domains and conventions codecheckers', 'oejskit django unittest nose doctest restdoc'), - ('internal, debugging, help functionality', + ('internal, debugging, help functionality', 'helpconfig terminal hooklog') - #('internal plugins / core functionality', + #('internal plugins / core functionality', # #'runner execnetcleanup # pytester', # 'runner execnetcleanup' # pytester', #) ] externals = { - 'oejskit': "run javascript tests in real life browsers", + 'oejskit': "run javascript tests in real life browsers", 'xdist': None, 'figleaf': None, - 'capturelog': None, - 'coverage': None, - 'cov': None, - 'codecheckers': None, - 'django': "for testing django applications", + 'capturelog': None, + 'coverage': None, + 'cov': None, + 'codecheckers': None, + 'django': "for testing django applications", } def warn(*args): @@ -107,7 +107,7 @@ class RestWriter: assert self._all_links[key] == link[1], (key, link[1]) else: self._all_links[key] = link[1] - + def write_all_links(cls, linkpath): p = linkpath.new(basename="links.txt") p_writer = RestWriter(p) @@ -142,7 +142,7 @@ class PluginOverview(RestWriter): self.add_internal_link(name, htmlpath) else: doc = PluginDoc(docpath) - doc.make(config=config, name=name) + doc.make(config=config, name=name) self.add_internal_link(name, doc.target) if name in externals: self.para("%s_ (external) %s" %(name, doc.oneliner)) @@ -173,9 +173,9 @@ class PluginDoc(RestWriter): moduledoc = doc[i+1:].strip() self.name = oneliner # plugin.__name__.split(".")[-1] - self.oneliner = oneliner + self.oneliner = oneliner self.moduledoc = moduledoc - + #self.h1("%s plugin" % self.name) # : %s" %(self.name, self.oneliner)) self.h1(oneliner) #self.Print(self.oneliner) @@ -185,13 +185,13 @@ class PluginDoc(RestWriter): self.Print() self.Print(moduledoc) - + self.emit_funcargs(plugin) self.emit_options(plugin) if name not in externals: self.emit_source(plugin, config.hg_changeset) - #self.sourcelink = (purename, - # "http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/" + + #self.sourcelink = (purename, + # "http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/" + # purename + ".py") # def emit_source(self, plugin, hg_changeset): @@ -199,35 +199,35 @@ class PluginDoc(RestWriter): if basename.endswith("pyc"): basename = basename[:-1] #self.para("`%s`_ source code" % basename) - #self.links.append((basename, + #self.links.append((basename, # "http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/" + # basename)) self.h1("Start improving this plugin in 30 seconds") self.para(py.code.Source(""" - 1. Download `%s`_ plugin source code - 2. put it somewhere as ``%s`` into your import path + 1. Download `%s`_ plugin source code + 2. put it somewhere as ``%s`` into your import path 3. a subsequent ``py.test`` run will use your local version - Checkout customize_, other plugins_ or `get in contact`_. + Checkout customize_, other plugins_ or `get in contact`_. """ % (basename, basename))) # your work appreciated if you offer back your version. In this case - # it probably makes sense if you `checkout the py.test + # it probably makes sense if you `checkout the py.test # development version`_ and apply your changes to the plugin - # version in there. - #self.links.append((basename, - # "http://bitbucket.org/hpk42/py-trunk/raw/%s/" + # version in there. + #self.links.append((basename, + # "http://bitbucket.org/hpk42/py-trunk/raw/%s/" # "py/test/plugin/%s" %(hg_changeset, basename))) - self.links.append((basename, - "http://bitbucket.org/hpk42/py-trunk/raw/%s/" + self.links.append((basename, + "http://bitbucket.org/hpk42/py-trunk/raw/%s/" "py/_plugin/%s" %(pyversion, basename))) self.links.append(('customize', '../customize.html')) self.links.append(('plugins', 'index.html')) self.links.append(('get in contact', '../../contact.html')) - self.links.append(('checkout the py.test development version', + self.links.append(('checkout the py.test development version', '../../install.html#checkout')) - + if 0: # this breaks the page layout and makes large doc files - #self.h2("plugin source code") + #self.h2("plugin source code") self.Print() self.para("For your convenience here is also an inlined version " "of ``%s``:" %basename) @@ -285,15 +285,15 @@ if __name__ == "__main__": pydir = py.path.local(py.__file__).dirpath() pyversion = py.version - cmd = "hg tip --template '{node}'" + cmd = "hg tip --template '{node}'" old = pydir.dirpath().chdir() _config.hg_changeset = py.process.cmdexec(cmd).strip() testdir = pydir.dirpath("doc", 'test') - + ov = PluginOverview(testdir.join("plugin", "index.txt")) ov.make(config=_config) - + ov = HookSpec(testdir.join("plugin", "hookspec.txt")) ov.make(config=_config) diff --git a/bin-for-dist/test_install.py b/bin-for-dist/test_install.py index a9c79128e..88821f10f 100644 --- a/bin-for-dist/test_install.py +++ b/bin-for-dist/test_install.py @@ -13,9 +13,9 @@ pytest_plugins = 'pytest_pytester', def pytest_funcarg__venv(request): p = request.config.mktemp(request.function.__name__, numbered=True) - venv = VirtualEnv(str(p)) - return venv - + venv = VirtualEnv(str(p)) + return venv + def pytest_funcarg__py_setup(request): testdir = request.getfuncargvalue('testdir') rootdir = py.path.local(py.__file__).dirpath().dirpath() @@ -48,14 +48,14 @@ class SetupBuilder: destdir = py.path.local(destdir) target = destdir.join(sdist.basename) sdist.copy(target) - return target + return target def subcall(args): if hasattr(subprocess, 'check_call'): subprocess.check_call(args) else: subprocess.call(args) -# code taken from Ronny Pfannenschmidt's virtualenvmanager +# code taken from Ronny Pfannenschmidt's virtualenvmanager class VirtualEnv(object): def __init__(self, path): @@ -119,7 +119,7 @@ class VirtualEnv(object): def test_make_sdist_and_run_it(py_setup, venv): sdist = py_setup.make_sdist(venv.path) - venv.easy_install(str(sdist)) + venv.easy_install(str(sdist)) gw = venv.makegateway() ch = gw.remote_exec("import py ; channel.send(py.__version__)") version = ch.receive() @@ -127,7 +127,7 @@ def test_make_sdist_and_run_it(py_setup, venv): def test_plugin_setuptools_entry_point_integration(py_setup, venv, tmpdir): sdist = py_setup.make_sdist(venv.path) - venv.easy_install(str(sdist)) + venv.easy_install(str(sdist)) # create a sample plugin basedir = tmpdir.mkdir("testplugin") basedir.join("setup.py").write("""if 1: @@ -151,7 +151,7 @@ def test_cmdline_entrypoints(monkeypatch): monkeypatch.syspath_prepend(py.path.local(__file__).dirpath().dirpath()) from setup import cmdline_entrypoints versioned_scripts = ['py.test', 'py.which'] - unversioned_scripts = versioned_scripts + [ 'py.cleanup', + unversioned_scripts = versioned_scripts + [ 'py.cleanup', 'py.convert_unittest', 'py.countloc', 'py.lookup', 'py.svnwcrevert'] for ver in [(2,4,0), (2,5,0), (2,6,0), (2,7,0), (3,0,1), (3,1,1)]: for platform in ('posix', 'win32'): @@ -187,7 +187,7 @@ def test_slave_popen_needs_no_pylib(testdir, venv, pytestconfig): def test_func(): pass """) - result = testdir.runpytest(p, '--rsyncdir=%s' % str(p), + result = testdir.runpytest(p, '--rsyncdir=%s' % str(p), '--dist=each', '--tx=popen//python=%s' % python) result.stdout.fnmatch_lines([ "*1 passed*" @@ -215,13 +215,13 @@ def test_slave_needs_no_execnet(testdir, sshhost, pytestconfig): ch = gw.remote_exec("import execnet") py.test.raises(ch.RemoteError, ch.waitclose) gw.exit() - + p = testdir.makepyfile(""" import py def test_func(): pass """) - result = testdir.runpytest(p, '--rsyncdir=%s' % str(p), + result = testdir.runpytest(p, '--rsyncdir=%s' % str(p), '--dist=each', '--tx=%s' % newspec) result.stdout.fnmatch_lines([ "*1 passed*" diff --git a/bin/_findpy.py b/bin/_findpy.py index 16992452a..56005153d 100755 --- a/bin/_findpy.py +++ b/bin/_findpy.py @@ -1,8 +1,8 @@ -#!/usr/bin/env python +#!/usr/bin/env python # # find and import a version of 'py' that exists in a parent dir -# of the current working directory. fall back to import a +# of the current working directory. fall back to import a # globally available version # import sys @@ -31,9 +31,9 @@ def searchpy(current): if not searchpy(abspath(os.curdir)): if not searchpy(opd(abspath(sys.argv[0]))): if not searchpy(opd(__file__)): - pass # let's hope it is just on sys.path + pass # let's hope it is just on sys.path import py -if __name__ == '__main__': +if __name__ == '__main__': print ("py lib is at %s" % py.__file__) diff --git a/conftest.py b/conftest.py index 83b986613..328b77756 100644 --- a/conftest.py +++ b/conftest.py @@ -12,7 +12,7 @@ pid = os.getpid() def pytest_addoption(parser): group = parser.getgroup("pylib", "py lib testing options") - group.addoption('--sshhost', + group.addoption('--sshhost', action="store", dest="sshhost", default=None, help=("ssh xspec for ssh functional tests. ")) group.addoption('--runslowtests', @@ -43,7 +43,7 @@ def pytest_funcarg__sshhost(request): val = request.config.getvalue("sshhost") if val: return val - py.test.skip("need --sshhost option") + py.test.skip("need --sshhost option") def pytest_generate_tests(metafunc): multi = getattr(metafunc.function, 'multi', None) if multi is not None: @@ -52,11 +52,11 @@ def pytest_generate_tests(metafunc): for val in l: metafunc.addcall(funcargs={name: val}) elif 'anypython' in metafunc.funcargnames: - for name in ('python2.4', 'python2.5', 'python2.6', + for name in ('python2.4', 'python2.5', 'python2.6', 'python2.7', 'python3.1', 'pypy-c', 'jython'): metafunc.addcall(id=name, param=name) -# XXX copied from execnet's conftest.py - needs to be merged +# XXX copied from execnet's conftest.py - needs to be merged winpymap = { 'python2.7': r'C:\Python27\python.exe', 'python2.6': r'C:\Python26\python.exe', @@ -73,7 +73,7 @@ def getexecutable(name, cache={}): if executable: if name == "jython": import subprocess - popen = subprocess.Popen([str(executable), "--version"], + popen = subprocess.Popen([str(executable), "--version"], universal_newlines=True, stderr=subprocess.PIPE) out, err = popen.communicate() if not err or "2.5" not in err: diff --git a/contrib/pytest_ignoreout.py b/contrib/pytest_ignoreout.py index b065593aa..8b9d25d19 100644 --- a/contrib/pytest_ignoreout.py +++ b/contrib/pytest_ignoreout.py @@ -5,4 +5,4 @@ def pytest_runtest_call(item, __multicall__): try: return __multicall__.execute() finally: - outerr = cap.reset() + outerr = cap.reset() diff --git a/contrib/pytest_resultdb.py b/contrib/pytest_resultdb.py index 04247f88e..57a8d272b 100644 --- a/contrib/pytest_resultdb.py +++ b/contrib/pytest_resultdb.py @@ -1,12 +1,12 @@ -"""XXX in progress: resultdb plugin for database logging of test results. +"""XXX in progress: resultdb plugin for database logging of test results. Saves test results to a datastore. XXX this needs to be merged with resultlog plugin -Also mixes in some early ideas about an archive abstraction for test +Also mixes in some early ideas about an archive abstraction for test results. -""" +""" import py py.test.skip("XXX needs to be merged with resultlog") @@ -15,15 +15,15 @@ from pytest_resultlog import ResultLog def pytest_addoption(parser): group = parser.addgroup("resultdb", "resultdb plugin options") - group.addoption('--resultdb', action="store", dest="resultdb", + group.addoption('--resultdb', action="store", dest="resultdb", metavar="path", help="path to the file to store test results.") - group.addoption('--resultdb_format', action="store", + group.addoption('--resultdb_format', action="store", dest="resultdbformat", default='json', help="data format (json, sqlite)") def pytest_configure(config): - # XXX using config.XYZ is not good + # XXX using config.XYZ is not good if config.getvalue('resultdb'): if config.option.resultdb: # local import so missing module won't crash py.test @@ -36,14 +36,14 @@ def pytest_configure(config): except ImportError: raise config.Error('Could not import simplejson module') if config.option.resultdbformat.lower() == 'json': - resultdb = ResultDB(JSONResultArchive, - config.option.resultdb) + resultdb = ResultDB(JSONResultArchive, + config.option.resultdb) elif config.option.resultdbformat.lower() == 'sqlite': - resultdb = ResultDB(SQLiteResultArchive, - config.option.resultdb) + resultdb = ResultDB(SQLiteResultArchive, + config.option.resultdb) else: - raise config.Error('Unknown --resultdb_format: %s' % - config.option.resultdbformat) + raise config.Error('Unknown --resultdb_format: %s' % + config.option.resultdbformat) config.pluginmanager.register(resultdb) @@ -52,7 +52,7 @@ class JSONResultArchive(object): self.archive_path = archive_path import simplejson self.simplejson = simplejson - + def init_db(self): if os.path.exists(self.archive_path): data_file = open(self.archive_path) @@ -84,7 +84,7 @@ class SQLiteResultArchive(object): self.archive_path = archive_path import sqlite3 self.sqlite3 = sqlite3 - + def init_db(self): if not os.path.exists(self.archive_path): conn = self.sqlite3.connect(self.archive_path) @@ -153,7 +153,7 @@ class ResultDB(ResultLog): for item in vars(event).keys(): if item not in event_excludes: data[item] = getattr(event, item) - # use the locally calculated longrepr & shortrepr + # use the locally calculated longrepr & shortrepr data['longrepr'] = longrepr data['shortrepr'] = shortrepr @@ -185,10 +185,10 @@ insert into pytest_results ( longrepr, fspath, itemname) -values (?, ?, ?, ?, ?, ?, ?, ?, ?); +values (?, ?, ?, ?, ?, ?, ?, ?, ?); """ SQL_SELECT_DATA = """ -select +select runid, name, passed, @@ -204,7 +204,7 @@ from pytest_results; # =============================================================================== # -# plugin tests +# plugin tests # # =============================================================================== @@ -214,7 +214,7 @@ class BaseResultArchiveTests(object): cls = None def setup_class(cls): - # XXX refactor setup into a funcarg? + # XXX refactor setup into a funcarg? cls.tempdb = "test_tempdb" def test_init_db(self, testdir): @@ -243,7 +243,7 @@ class BaseResultArchiveTests(object): for key, value in data[0].items(): assert value == result[0][key] assert 'runid' in result[0] - + # make sure the data is persisted tempdb_path = unicode(testdir.tmpdir.join(self.tempdb)) archive = self.cls(tempdb_path) @@ -257,7 +257,7 @@ class TestJSONResultArchive(BaseResultArchiveTests): def setup_method(self, method): py.test.importorskip("simplejson") - + class TestSQLiteResultArchive(BaseResultArchiveTests): cls = SQLiteResultArchive @@ -270,8 +270,8 @@ class TestSQLiteResultArchive(BaseResultArchiveTests): archive = self.cls(tempdb_path) archive.init_db() assert os.path.exists(tempdb_path) - - # is table in the database? + + # is table in the database? import sqlite3 conn = sqlite3.connect(tempdb_path) cursor = conn.cursor() @@ -281,7 +281,7 @@ class TestSQLiteResultArchive(BaseResultArchiveTests): cursor.close() conn.close() assert len(tables) == 1 - + def verify_archive_item_shape(item): names = ("runid name passed skipped failed shortrepr " "longrepr fspath itemname").split() @@ -299,14 +299,14 @@ class TestWithFunctionIntegration: archive = SQLiteResultArchive(unicode(resultdb)) archive.init_db() return archive - + def test_collection_report(self, testdir): py.test.skip("Needs a rewrite for db version.") ok = testdir.makepyfile(test_collection_ok="") skip = testdir.makepyfile(test_collection_skip="import py ; py.test.skip('hello')") fail = testdir.makepyfile(test_collection_fail="XXX") - lines = self.getresultdb(testdir, ok) + lines = self.getresultdb(testdir, ok) assert not lines lines = self.getresultdb(testdir, skip) @@ -326,7 +326,7 @@ class TestWithFunctionIntegration: def test_log_test_outcomes(self, testdir): mod = testdir.makepyfile(test_mod=""" - import py + import py def test_pass(): pass def test_skip(): py.test.skip("hello") def test_fail(): raise ValueError("val") @@ -349,7 +349,7 @@ class TestWithFunctionIntegration: raise ValueError except ValueError: excinfo = py.code.ExceptionInfo() - reslog = ResultDB(StringIO.StringIO()) + reslog = ResultDB(StringIO.StringIO()) reslog.pytest_internalerror(excinfo.getrepr) entry = reslog.logfile.getvalue() entry_lines = entry.splitlines() @@ -357,7 +357,7 @@ class TestWithFunctionIntegration: assert entry_lines[0].startswith('! ') assert os.path.basename(__file__)[:-1] in entry_lines[0] #.py/.pyc assert entry_lines[-1][0] == ' ' - assert 'ValueError' in entry + assert 'ValueError' in entry def test_generic(testdir): testdir.makepyfile(""" @@ -371,4 +371,4 @@ def test_generic(testdir): """) testdir.runpytest("--resultdb=result.sqlite") #testdir.tmpdir.join("result.sqlite") - + diff --git a/contrib/pytest_twisted/__init__.py b/contrib/pytest_twisted/__init__.py index 40a6783b7..9b568f531 100644 --- a/contrib/pytest_twisted/__init__.py +++ b/contrib/pytest_twisted/__init__.py @@ -20,7 +20,7 @@ try: from greenlet import greenlet except ImportError: print "Since pylib 1.0 greenlet are removed and separately packaged: " \ - "http://pypi.python.org/pypi/greenlet" + "http://pypi.python.org/pypi/greenlet" sys.exit(10) @@ -44,7 +44,7 @@ def _run_twisted(logging=False): failure.Failure.cleanFailure = lambda *args: None if logging: _start_twisted_logging() - + def fix_signal_handling(): # see http://twistedmatrix.com/trac/ticket/733 import signal @@ -54,7 +54,7 @@ def _run_twisted(logging=False): def start(): fix_signal_handling() doit(None) - + # recursively called for each test-function/method due done() def doit(val): # val always None # switch context to wait that wrapper() passes back to test-method @@ -68,7 +68,7 @@ def _run_twisted(logging=False): def err(res): reactor.callLater(0.0, doit, res) - + # the test-function *may* return a deferred # here the test-function will actually been called # done() is finalizing a test-process by assuring recursive invoking @@ -92,19 +92,19 @@ def pytest_unconfigure(config): gr_twisted.switch(None) def pytest_pyfunc_call(pyfuncitem): - # XXX1 kwargs? + # XXX1 kwargs? # XXX2 we want to delegate actual call to next plugin - # (which may want to produce test coverage, etc.) + # (which may want to produce test coverage, etc.) res = gr_twisted.switch(lambda: pyfuncitem.call()) if res: res.raiseException() - return True # indicates that we performed the function call + return True # indicates that we performed the function call gr_twisted = greenlet(_run_twisted) gr_tests = greenlet.getcurrent() # =============================================================================== -# plugin tests +# plugin tests # =============================================================================== def test_generic(testdir): @@ -125,7 +125,7 @@ def test_generic(testdir): def done(): log.msg("test_deferred.done() CALLBACK DONE") d.callback(None) - + reactor.callLater(2.5, done) log.msg("test_deferred() returning deferred: %r" % (d,)) return d @@ -136,7 +136,7 @@ def test_generic(testdir): def done(): log.msg("test_deferred2.done() CALLBACK DONE") d.callback(None) - + reactor.callLater(2.5, done) log.msg("test_deferred2() returning deferred: %r" % (d,)) return d @@ -157,7 +157,7 @@ def test_generic(testdir): def done(): log.msg("test_deferred3.done() CALLBACK DONE") d.callback(None) - + reactor.callLater(2.5, done) log.msg("test_deferred3() returning deferred: %r" % (d,)) return d @@ -172,7 +172,7 @@ def test_generic(testdir): def done(): log.msg("TestTwistedSetupMethod.test_deferred() CALLBACK DONE") d.callback(None) - + reactor.callLater(2.5, done) log.msg("TestTwistedSetupMethod.test_deferred() returning deferred: %r" % (d,)) return d diff --git a/contrib/readme.txt b/contrib/readme.txt index 26ac5f9af..f120945c3 100644 --- a/contrib/readme.txt +++ b/contrib/readme.txt @@ -1,2 +1,2 @@ -pygreen: experimental IO and execnet operations through greenlets +pygreen: experimental IO and execnet operations through greenlets diff --git a/contrib/runtesthelper.py b/contrib/runtesthelper.py index e1c769e0c..9e3f1c1ff 100644 --- a/contrib/runtesthelper.py +++ b/contrib/runtesthelper.py @@ -1,10 +1,10 @@ """ this little helper allows to run tests multiple times -in the same process. useful for running tests from -a console. +in the same process. useful for running tests from +a console. -NOTE: since 1.3.1 you can just call py.test.cmdline.main() -multiple times - no special logic needed. +NOTE: since 1.3.1 you can just call py.test.cmdline.main() +multiple times - no special logic needed. """ import py, sys diff --git a/doc/announce/release-0.9.0.txt b/doc/announce/release-0.9.0.txt index 8adf46347..071093135 100644 --- a/doc/announce/release-0.9.0.txt +++ b/doc/announce/release-0.9.0.txt @@ -1,7 +1,7 @@ py lib 1.0.0: XXX ====================================================================== -Welcome to the 1.0.0 py lib release - a library aiming to -support agile and test-driven python development on various levels. +Welcome to the 1.0.0 py lib release - a library aiming to +support agile and test-driven python development on various levels. XXX diff --git a/doc/announce/release-0.9.2.txt b/doc/announce/release-0.9.2.txt index 88bd1bbb3..bc2d2ef29 100644 --- a/doc/announce/release-0.9.2.txt +++ b/doc/announce/release-0.9.2.txt @@ -1,17 +1,17 @@ py lib 0.9.2: bugfix release ============================= -Welcome to the 0.9.2 py lib and py.test release - +Welcome to the 0.9.2 py lib and py.test release - mainly fixing Windows issues, providing better packaging and integration with setuptools. -Here is a quick summary of what the py lib provides: +Here is a quick summary of what the py lib provides: * py.test: cross-project testing tool with many advanced features * py.execnet: ad-hoc code distribution to SSH, Socket and local sub processes * py.magic.greenlet: micro-threads on standard CPython ("stackless-light") -* py.path: path abstractions over local and subversion files -* rich documentation of py's exported API +* py.path: path abstractions over local and subversion files +* rich documentation of py's exported API * tested against Linux, Win32, OSX, works on python 2.3-2.6 See here for more information: diff --git a/doc/announce/release-1.0.0.txt b/doc/announce/release-1.0.0.txt index fd7b9c7e1..7024255a1 100644 --- a/doc/announce/release-1.0.0.txt +++ b/doc/announce/release-1.0.0.txt @@ -9,47 +9,47 @@ many new advanced automated testing features - here is a quick summary: * funcargs_ - pythonic zero-boilerplate fixtures for Python test functions : - - totally separates test code, test configuration and test setup + - totally separates test code, test configuration and test setup - ideal for integration and functional tests - allows for flexible and natural test parametrization schemes -* new `plugin architecture`_, allowing easy-to-write project-specific and cross-project single-file plugins. The most notable new external plugin is `oejskit`_ which naturally enables **running and reporting of javascript-unittests in real-life browsers**. +* new `plugin architecture`_, allowing easy-to-write project-specific and cross-project single-file plugins. The most notable new external plugin is `oejskit`_ which naturally enables **running and reporting of javascript-unittests in real-life browsers**. * many new features done in easy-to-improve `default plugins`_, highlights: * xfail: mark tests as "expected to fail" and report separately. - * pastebin: automatically send tracebacks to pocoo paste service + * pastebin: automatically send tracebacks to pocoo paste service * capture: flexibly capture stdout/stderr of subprocesses, per-test ... * monkeypatch: safely monkeypatch modules/classes from within tests - * unittest: run and integrate traditional unittest.py tests + * unittest: run and integrate traditional unittest.py tests * figleaf: generate html coverage reports with the figleaf module - * resultlog: generate buildbot-friendly reporting output + * resultlog: generate buildbot-friendly reporting output * ... -* `distributed testing`_ and `elastic distributed execution`_: +* `distributed testing`_ and `elastic distributed execution`_: - - new unified "TX" URL scheme for specifying remote processes - - new distribution modes "--dist=each" and "--dist=load" - - new sync/async ways to handle 1:N communication - - improved documentation + - new unified "TX" URL scheme for specifying remote processes + - new distribution modes "--dist=each" and "--dist=load" + - new sync/async ways to handle 1:N communication + - improved documentation The py lib continues to offer most of the functionality used by -the testing tool in `independent namespaces`_. +the testing tool in `independent namespaces`_. Some non-test related code, notably greenlets/co-routines and api-generation now live as their own projects which simplifies the -installation procedure because no C-Extensions are required anymore. +installation procedure because no C-Extensions are required anymore. The whole package should work well with Linux, Win32 and OSX, on Python -2.3, 2.4, 2.5 and 2.6. (Expect Python3 compatibility soon!) +2.3, 2.4, 2.5 and 2.6. (Expect Python3 compatibility soon!) -For more info, see the py.test and py lib documentation: +For more info, see the py.test and py lib documentation: http://pytest.org http://pylib.org -have fun, +have fun, holger .. _`independent namespaces`: http://pylib.org @@ -58,6 +58,6 @@ holger .. _`default plugins`: http://codespeak.net/py/dist/test/plugin/index.html .. _`distributed testing`: http://codespeak.net/py/dist/test/dist.html .. _`elastic distributed execution`: http://codespeak.net/py/dist/execnet.html -.. _`1.0.0 py lib release`: http://pypi.python.org/pypi/py +.. _`1.0.0 py lib release`: http://pypi.python.org/pypi/py .. _`oejskit`: http://codespeak.net/py/dist/test/plugin/oejskit.html diff --git a/doc/announce/release-1.0.1.txt b/doc/announce/release-1.0.1.txt index 0b4beb1e1..0c9f8760b 100644 --- a/doc/announce/release-1.0.1.txt +++ b/doc/announce/release-1.0.1.txt @@ -1,48 +1,48 @@ 1.0.1: improved reporting, nose/unittest.py support, bug fixes ----------------------------------------------------------------------- -This is a bugfix release of pylib/py.test also coming with: +This is a bugfix release of pylib/py.test also coming with: -* improved documentation, improved navigation +* improved documentation, improved navigation * test failure reporting improvements * support for directly running existing nose/unittest.py style tests -visit here for more info, including quickstart and tutorials: +visit here for more info, including quickstart and tutorials: http://pytest.org and http://pylib.org -Changelog 1.0.0 to 1.0.1 +Changelog 1.0.0 to 1.0.1 ------------------------ -* added a default 'pytest_nose' plugin which handles nose.SkipTest, - nose-style function/method/generator setup/teardown and - tries to report functions correctly. +* added a default 'pytest_nose' plugin which handles nose.SkipTest, + nose-style function/method/generator setup/teardown and + tries to report functions correctly. -* improved documentation, better navigation: see http://pytest.org +* improved documentation, better navigation: see http://pytest.org * added a "--help-config" option to show conftest.py / ENV-var names for - all longopt cmdline options, and some special conftest.py variables. - renamed 'conf_capture' conftest setting to 'option_capture' accordingly. + all longopt cmdline options, and some special conftest.py variables. + renamed 'conf_capture' conftest setting to 'option_capture' accordingly. -* unicode fixes: capturing and unicode writes to sys.stdout - (through e.g a print statement) now work within tests, - they are encoded as "utf8" by default, also terminalwriting - was adapted and somewhat unified between windows and linux +* unicode fixes: capturing and unicode writes to sys.stdout + (through e.g a print statement) now work within tests, + they are encoded as "utf8" by default, also terminalwriting + was adapted and somewhat unified between windows and linux -* fix issue #27: better reporting on non-collectable items given on commandline +* fix issue #27: better reporting on non-collectable items given on commandline (e.g. pyc files) -* fix issue #33: added --version flag (thanks Benjamin Peterson) +* fix issue #33: added --version flag (thanks Benjamin Peterson) * fix issue #32: adding support for "incomplete" paths to wcpath.status() -* "Test" prefixed classes are *not* collected by default anymore if they - have an __init__ method +* "Test" prefixed classes are *not* collected by default anymore if they + have an __init__ method * monkeypatch setenv() now accepts a "prepend" parameter * improved reporting of collection error tracebacks -* simplified multicall mechanism and plugin architecture, - renamed some internal methods and argnames +* simplified multicall mechanism and plugin architecture, + renamed some internal methods and argnames diff --git a/doc/announce/release-1.0.2.txt b/doc/announce/release-1.0.2.txt index 1a9163fac..235461953 100644 --- a/doc/announce/release-1.0.2.txt +++ b/doc/announce/release-1.0.2.txt @@ -1,4 +1,4 @@ -1.0.2: packaging fixes +1.0.2: packaging fixes ----------------------------------------------------------------------- this release is purely a release for fixing packaging issues. diff --git a/doc/announce/release-1.1.0.txt b/doc/announce/release-1.1.0.txt index b3b27989c..0441c3215 100644 --- a/doc/announce/release-1.1.0.txt +++ b/doc/announce/release-1.1.0.txt @@ -1,4 +1,4 @@ -py.test/pylib 1.1.0: Python3, Jython, advanced skipping, cleanups ... +py.test/pylib 1.1.0: Python3, Jython, advanced skipping, cleanups ... -------------------------------------------------------------------------------- Features: @@ -10,16 +10,16 @@ Features: Fixes: * code reduction and "de-magification" (e.g. 23 KLoc -> 11 KLOC) -* distribute testing requires the now separately released execnet_ package +* distribute testing requires the now separately released execnet_ package * funcarg-setup/caching, "same-name" test modules now cause an exlicit error -* de-cluttered reporting options, --report for skipped/xfail details +* de-cluttered reporting options, --report for skipped/xfail details Compatibilities -1.1.0 should allow running test code that already worked well with 1.0.2 -plus some more due to improved unittest/nose compatibility. +1.1.0 should allow running test code that already worked well with 1.0.2 +plus some more due to improved unittest/nose compatibility. -More information: http://pytest.org +More information: http://pytest.org thanks and have fun, @@ -36,16 +36,16 @@ Changelog 1.0.2 -> 1.1.0 * remove py.rest tool and internal namespace - it was never really advertised and can still be used with - the old release if needed. If there is interest + the old release if needed. If there is interest it could be revived into its own tool i guess. * fix issue48 and issue59: raise an Error if the module - from an imported test file does not seem to come from + from an imported test file does not seem to come from the filepath - avoids "same-name" confusion that has been reported repeatedly * merged Ronny's nose-compatibility hacks: now - nose-style setup_module() and setup() functions are + nose-style setup_module() and setup() functions are supported * introduce generalized py.test.mark function marking @@ -54,62 +54,62 @@ Changelog 1.0.2 -> 1.1.0 * deprecate parser.addgroup in favour of getgroup which creates option group -* add --report command line option that allows to control showing of skipped/xfailed sections +* add --report command line option that allows to control showing of skipped/xfailed sections -* generalized skipping: a new way to mark python functions with skipif or xfail - at function, class and modules level based on platform or sys-module attributes. +* generalized skipping: a new way to mark python functions with skipif or xfail + at function, class and modules level based on platform or sys-module attributes. * extend py.test.mark decorator to allow for positional args -* introduce and test "py.cleanup -d" to remove empty directories +* introduce and test "py.cleanup -d" to remove empty directories * fix issue #59 - robustify unittest test collection -* make bpython/help interaction work by adding an __all__ attribute +* make bpython/help interaction work by adding an __all__ attribute to ApiModule, cleanup initpkg * use MIT license for pylib, add some contributors * remove py.execnet code and substitute all usages with 'execnet' proper -* fix issue50 - cached_setup now caches more to expectations - for test functions with multiple arguments. +* fix issue50 - cached_setup now caches more to expectations + for test functions with multiple arguments. * merge Jarko's fixes, issue #45 and #46 * add the ability to specify a path for py.lookup to search in -* fix a funcarg cached_setup bug probably only occuring - in distributed testing and "module" scope with teardown. +* fix a funcarg cached_setup bug probably only occuring + in distributed testing and "module" scope with teardown. * many fixes and changes for making the code base python3 compatible, - many thanks to Benjamin Peterson for helping with this. + many thanks to Benjamin Peterson for helping with this. -* consolidate builtins implementation to be compatible with >=2.3, +* consolidate builtins implementation to be compatible with >=2.3, add helpers to ease keeping 2 and 3k compatible code * deprecate py.compat.doctest|subprocess|textwrap|optparse -* deprecate py.magic.autopath, remove py/magic directory +* deprecate py.magic.autopath, remove py/magic directory * move pytest assertion handling to py/code and a pytest_assertion - plugin, add "--no-assert" option, deprecate py.magic namespaces - in favour of (less) py.code ones. + plugin, add "--no-assert" option, deprecate py.magic namespaces + in favour of (less) py.code ones. -* consolidate and cleanup py/code classes and files +* consolidate and cleanup py/code classes and files -* cleanup py/misc, move tests to bin-for-dist +* cleanup py/misc, move tests to bin-for-dist -* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg +* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg -* consolidate py.log implementation, remove old approach. +* consolidate py.log implementation, remove old approach. * introduce py.io.TextIO and py.io.BytesIO for distinguishing between - text/unicode and byte-streams (uses underlying standard lib io.* - if available) + text/unicode and byte-streams (uses underlying standard lib io.* + if available) -* make py.unittest_convert helper script available which converts "unittest.py" +* make py.unittest_convert helper script available which converts "unittest.py" style files into the simpler assert/direct-test-classes py.test/nosetests - style. The script was written by Laura Creighton. - -* simplified internal localpath implementation + style. The script was written by Laura Creighton. + +* simplified internal localpath implementation diff --git a/doc/announce/release-1.1.1.txt b/doc/announce/release-1.1.1.txt index 3fe780566..83e6a1fd8 100644 --- a/doc/announce/release-1.1.1.txt +++ b/doc/announce/release-1.1.1.txt @@ -5,19 +5,19 @@ This is a compatibility fixing release of pylib/py.test to work better with previous 1.0.x test code bases. It also contains fixes and changes to work with `execnet>=1.0.0`_ to provide distributed testing and looponfailing testing modes. py-1.1.1 also introduces -a new mechanism for registering plugins via setuptools. +a new mechanism for registering plugins via setuptools. -What is pylib/py.test? +What is pylib/py.test? ----------------------- py.test is an advanced automated testing tool working with Python2, Python3 and Jython versions on all major operating -systems. It has an extensive plugin architecture and can run many +systems. It has an extensive plugin architecture and can run many existing common Python test suites without modification. Moreover, it offers some unique features not found in other testing tools. See http://pytest.org for more info. -The pylib also contains a localpath and svnpath implementation +The pylib also contains a localpath and svnpath implementation and some developer-oriented command line tools. See http://pylib.org for more info. @@ -31,15 +31,15 @@ holger (http://twitter.com/hpk42) Changes between 1.1.1 and 1.1.0 ===================================== -- introduce automatic plugin registration via 'pytest11' +- introduce automatic plugin registration via 'pytest11' entrypoints via setuptools' pkg_resources.iter_entry_points -- fix py.test dist-testing to work with execnet >= 1.0.0b4 +- fix py.test dist-testing to work with execnet >= 1.0.0b4 -- re-introduce py.test.cmdline.main() for better backward compatibility +- re-introduce py.test.cmdline.main() for better backward compatibility - svn paths: fix a bug with path.check(versioned=True) for svn paths, - allow '%' in svn paths, make svnwc.update() default to interactive mode + allow '%' in svn paths, make svnwc.update() default to interactive mode like in 1.0.x and add svnwc.update(interactive=False) to inhibit interaction. - refine distributed tarball to contain test and no pyc files diff --git a/doc/announce/release-1.2.0.txt b/doc/announce/release-1.2.0.txt index 25761cb5c..4f6a56144 100644 --- a/doc/announce/release-1.2.0.txt +++ b/doc/announce/release-1.2.0.txt @@ -3,28 +3,28 @@ py.test/pylib 1.2.0: junitxml, standalone test scripts, pluginization py.test is an advanced automated testing tool working with Python2, Python3 and Jython versions on all major operating -systems. It has a simple plugin architecture and can run many -existing common Python test suites without modification. It offers -some unique features not found in other testing tools. +systems. It has a simple plugin architecture and can run many +existing common Python test suites without modification. It offers +some unique features not found in other testing tools. See http://pytest.org for more info. py.test 1.2.0 brings many bug fixes and interesting new abilities: -* --junitxml=path will create an XML file for use with CI processing -* --genscript=path creates a standalone py.test-equivalent test-script +* --junitxml=path will create an XML file for use with CI processing +* --genscript=path creates a standalone py.test-equivalent test-script * --ignore=path prevents collection of anything below that path * --confcutdir=path only lookup conftest.py test configs below that path -* a 'pytest_report_header' hook to add info to the terminal report header +* a 'pytest_report_header' hook to add info to the terminal report header * a 'pytestconfig' function argument gives direct access to option values -* 'pytest_generate_tests' can now be put into a class as well +* 'pytest_generate_tests' can now be put into a class as well * on CPython py.test additionally installs as "py.test-VERSION", on Jython as py.test-jython and on PyPy as py.test-pypy-XYZ -Apart from many bug fixes 1.2.0 also has better pluginization: +Apart from many bug fixes 1.2.0 also has better pluginization: Distributed testing and looponfailing testing now live in the separately installable 'pytest-xdist' plugin. The same is true for 'pytest-figleaf' for doing coverage reporting. Those two plugins -can serve well now as blue prints for doing your own. +can serve well now as blue prints for doing your own. thanks to all who helped and gave feedback, have fun, @@ -34,45 +34,45 @@ holger krekel, January 2010 Changes between 1.2.0 and 1.1.1 ===================================== -- moved dist/looponfailing from py.test core into a new +- moved dist/looponfailing from py.test core into a new separately released pytest-xdist plugin. - new junitxml plugin: --junitxml=path will generate a junit style xml file - which is processable e.g. by the Hudson CI system. + which is processable e.g. by the Hudson CI system. - new option: --genscript=path will generate a standalone py.test script - which will not need any libraries installed. thanks to Ralf Schmitt. + which will not need any libraries installed. thanks to Ralf Schmitt. -- new option: --ignore will prevent specified path from collection. - Can be specified multiple times. +- new option: --ignore will prevent specified path from collection. + Can be specified multiple times. -- new option: --confcutdir=dir will make py.test only consider conftest - files that are relative to the specified dir. +- new option: --confcutdir=dir will make py.test only consider conftest + files that are relative to the specified dir. - new funcarg: "pytestconfig" is the pytest config object for access - to command line args and can now be easily used in a test. + to command line args and can now be easily used in a test. - install 'py.test' and `py.which` with a ``-$VERSION`` suffix to - disambiguate between Python3, python2.X, Jython and PyPy installed versions. + disambiguate between Python3, python2.X, Jython and PyPy installed versions. - new "pytestconfig" funcarg allows access to test config object -- new "pytest_report_header" hook can return additional lines - to be displayed at the header of a test run. +- new "pytest_report_header" hook can return additional lines + to be displayed at the header of a test run. - (experimental) allow "py.test path::name1::name2::..." for pointing to a test within a test collection directly. This might eventually - evolve as a full substitute to "-k" specifications. + evolve as a full substitute to "-k" specifications. - streamlined plugin loading: order is now as documented in - customize.html: setuptools, ENV, commandline, conftest. + customize.html: setuptools, ENV, commandline, conftest. also setuptools entry point names are turned to canonical namees ("pytest_*") -- automatically skip tests that need 'capfd' but have no os.dup +- automatically skip tests that need 'capfd' but have no os.dup -- allow pytest_generate_tests to be defined in classes as well +- allow pytest_generate_tests to be defined in classes as well -- deprecate usage of 'disabled' attribute in favour of pytestmark +- deprecate usage of 'disabled' attribute in favour of pytestmark - deprecate definition of Directory, Module, Class and Function nodes in conftest.py files. Use pytest collect hooks instead. @@ -87,28 +87,28 @@ Changes between 1.2.0 and 1.1.1 change its long command line options to be a bit shorter (see py.test -h). - change: pytest doctest plugin is now enabled by default and has a - new option --doctest-glob to set a pattern for file matches. + new option --doctest-glob to set a pattern for file matches. -- change: remove internal py._* helper vars, only keep py._pydir +- change: remove internal py._* helper vars, only keep py._pydir -- robustify capturing to survive if custom pytest_runtest_setup - code failed and prevented the capturing setup code from running. +- robustify capturing to survive if custom pytest_runtest_setup + code failed and prevented the capturing setup code from running. - make py.test.* helpers provided by default plugins visible early - works transparently both for pydoc and for interactive sessions - which will regularly see e.g. py.test.mark and py.test.importorskip. + which will regularly see e.g. py.test.mark and py.test.importorskip. -- simplify internal plugin manager machinery +- simplify internal plugin manager machinery - simplify internal collection tree by introducing a RootCollector node - fix assert reinterpreation that sees a call containing "keyword=..." -- fix issue66: invoke pytest_sessionstart and pytest_sessionfinish - hooks on slaves during dist-testing, report module/session teardown +- fix issue66: invoke pytest_sessionstart and pytest_sessionfinish + hooks on slaves during dist-testing, report module/session teardown hooks correctly. -- fix issue65: properly handle dist-testing if no - execnet/py lib installed remotely. +- fix issue65: properly handle dist-testing if no + execnet/py lib installed remotely. - skip some install-tests if no execnet is available diff --git a/doc/announce/release-1.2.1.txt b/doc/announce/release-1.2.1.txt index 9c543614b..5bf8ba22d 100644 --- a/doc/announce/release-1.2.1.txt +++ b/doc/announce/release-1.2.1.txt @@ -1,29 +1,29 @@ -py.test/pylib 1.2.1: little fixes and improvements +py.test/pylib 1.2.1: little fixes and improvements -------------------------------------------------------------------------------- py.test is an advanced automated testing tool working with Python2, Python3 and Jython versions on all major operating -systems. It has a simple plugin architecture and can run many -existing common Python test suites without modification. It offers -some unique features not found in other testing tools. +systems. It has a simple plugin architecture and can run many +existing common Python test suites without modification. It offers +some unique features not found in other testing tools. See http://pytest.org for more info. -py.test 1.2.1 brings bug fixes and some new options and abilities triggered +py.test 1.2.1 brings bug fixes and some new options and abilities triggered by user feedback: * --funcargs [testpath] will show available builtin- and project funcargs. * display a short and concise traceback if funcarg lookup fails. -* early-load "conftest.py" files in non-dot first-level sub directories. +* early-load "conftest.py" files in non-dot first-level sub directories. * --tb=line will print a single line for each failing test (issue67) * py.cleanup has a number of new options, cleanups up setup.py related files * fix issue78: always call python-level teardown functions even if the - according setup failed. + according setup failed. -For more detailed information see the changelog below. +For more detailed information see the changelog below. cheers and have fun, -holger +holger Changes between 1.2.1 and 1.2.0 @@ -34,33 +34,33 @@ Changes between 1.2.1 and 1.2.0 py.cleanup # remove "*.pyc" and "*$py.class" (jython) files py.cleanup -e .swp -e .cache # also remove files with these extensions py.cleanup -s # remove "build" and "dist" directory next to setup.py files - py.cleanup -d # also remove empty directories + py.cleanup -d # also remove empty directories py.cleanup -a # synonym for "-s -d -e 'pip-log.txt'" py.cleanup -n # dry run, only show what would be removed -- add a new option "py.test --funcargs" which shows available funcargs - and their help strings (docstrings on their respective factory function) +- add a new option "py.test --funcargs" which shows available funcargs + and their help strings (docstrings on their respective factory function) for a given test path -- display a short and concise traceback if a funcarg lookup fails +- display a short and concise traceback if a funcarg lookup fails -- early-load "conftest.py" files in non-dot first-level sub directories. - allows to conveniently keep and access test-related options in a ``test`` - subdir and still add command line options. +- early-load "conftest.py" files in non-dot first-level sub directories. + allows to conveniently keep and access test-related options in a ``test`` + subdir and still add command line options. - fix issue67: new super-short traceback-printing option: "--tb=line" will print a single line for each failing (python) test indicating its filename, lineno and the failure value - fix issue78: always call python-level teardown functions even if the - according setup failed. This includes refinements for calling setup_module/class functions + according setup failed. This includes refinements for calling setup_module/class functions which will now only be called once instead of the previous behaviour where they'd be called multiple times if they raise an exception (including a Skipped exception). Any exception will be re-corded and associated with all tests in the according module/class scope. - fix issue63: assume <40 columns to be a bogus terminal width, default to 80 -- fix pdb debugging to be in the correct frame on raises-related errors +- fix pdb debugging to be in the correct frame on raises-related errors - update apipkg.py to fix an issue where recursive imports might - unnecessarily break importing + unnecessarily break importing -- fix plugin links +- fix plugin links diff --git a/doc/announce/release-1.3.0.txt b/doc/announce/release-1.3.0.txt index 1f2be80b4..cf97db036 100644 --- a/doc/announce/release-1.3.0.txt +++ b/doc/announce/release-1.3.0.txt @@ -1,10 +1,10 @@ -py.test/pylib 1.3.0: new options, per-plugin hooks, fixes ... +py.test/pylib 1.3.0: new options, per-plugin hooks, fixes ... =========================================================================== -The 1.3.0 release introduces new options, bug fixes and improved compatibility +The 1.3.0 release introduces new options, bug fixes and improved compatibility with Python3 and Jython-2.5.1 on Windows. If you already use py-1.2 chances -are you can use py-1.3.0. See the below CHANGELOG for more details and -http://pylib.org/install.html for installation instructions. +are you can use py-1.3.0. See the below CHANGELOG for more details and +http://pylib.org/install.html for installation instructions. py.test is an advanced automated testing tool working with Python2, Python3, Jython and PyPy versions on all major operating systems. It @@ -12,7 +12,7 @@ offers a no-boilerplate testing approach and has inspired other testing tools and enhancements in the standard Python library for more than five years. It has a simple and extensive plugin architecture, configurable reporting and provides unique ways to make it fit to your testing -process and needs. +process and needs. See http://pytest.org for more info. @@ -26,28 +26,28 @@ Changes between 1.2.1 and 1.3.0 - deprecate --report option in favour of a new shorter and easier to remember -r option: it takes a string argument consisting of any combination of 'xfsX' characters. They relate to the single chars - you see during the dotted progress printing and will print an extra line + you see during the dotted progress printing and will print an extra line per test at the end of the test run. This extra line indicates the exact position or test ID that you directly paste to the py.test cmdline in order - to re-run a particular test. + to re-run a particular test. -- allow external plugins to register new hooks via the new +- allow external plugins to register new hooks via the new pytest_addhooks(pluginmanager) hook. The new release of - the pytest-xdist plugin for distributed and looponfailing - testing requires this feature. + the pytest-xdist plugin for distributed and looponfailing + testing requires this feature. - add a new pytest_ignore_collect(path, config) hook to allow projects and - plugins to define exclusion behaviour for their directory structure - + plugins to define exclusion behaviour for their directory structure - for example you may define in a conftest.py this method:: def pytest_ignore_collect(path): return path.check(link=1) - to prevent even collection of any tests in symlinked dirs. + to prevent even collection of any tests in symlinked dirs. - new pytest_pycollect_makemodule(path, parent) hook for - allowing customization of the Module collection object for a - matching test module. + allowing customization of the Module collection object for a + matching test module. - extend and refine xfail mechanism:: @@ -55,14 +55,14 @@ Changes between 1.2.1 and 1.3.0 @py.test.mark.xfail(reason="...") prints the reason string in xfail summaries specifiying ``--runxfail`` on command line ignores xfail markers to show - you the underlying traceback. + you the underlying traceback. -- expose (previously internal) commonly useful methods: +- expose (previously internal) commonly useful methods: py.io.get_terminal_with() -> return terminal width py.io.ansi_print(...) -> print colored/bold text on linux/win32 py.io.saferepr(obj) -> return limited representation string -- expose test outcome related exceptions as py.test.skip.Exception, +- expose test outcome related exceptions as py.test.skip.Exception, py.test.raises.Exception etc., useful mostly for plugins doing special outcome interpretation/tweaking @@ -70,22 +70,22 @@ Changes between 1.2.1 and 1.3.0 - fix/refine python3 compatibility (thanks Benjamin Peterson) -- fixes for making the jython/win32 combination work, note however: +- fixes for making the jython/win32 combination work, note however: jython2.5.1/win32 does not provide a command line launcher, see http://bugs.jython.org/issue1491 . See pylib install documentation - for how to work around. + for how to work around. - fixes for handling of unicode exception values and unprintable objects -- (issue87) fix unboundlocal error in assertionold code +- (issue87) fix unboundlocal error in assertionold code - (issue86) improve documentation for looponfailing - refine IO capturing: stdin-redirect pseudo-file now has a NOP close() method -- ship distribute_setup.py version 0.6.10 +- ship distribute_setup.py version 0.6.10 -- added links to the new capturelog and coverage plugins +- added links to the new capturelog and coverage plugins Changes between 1.2.1 and 1.2.0 @@ -96,79 +96,79 @@ Changes between 1.2.1 and 1.2.0 py.cleanup # remove "*.pyc" and "*$py.class" (jython) files py.cleanup -e .swp -e .cache # also remove files with these extensions py.cleanup -s # remove "build" and "dist" directory next to setup.py files - py.cleanup -d # also remove empty directories + py.cleanup -d # also remove empty directories py.cleanup -a # synonym for "-s -d -e 'pip-log.txt'" py.cleanup -n # dry run, only show what would be removed -- add a new option "py.test --funcargs" which shows available funcargs - and their help strings (docstrings on their respective factory function) +- add a new option "py.test --funcargs" which shows available funcargs + and their help strings (docstrings on their respective factory function) for a given test path -- display a short and concise traceback if a funcarg lookup fails +- display a short and concise traceback if a funcarg lookup fails -- early-load "conftest.py" files in non-dot first-level sub directories. - allows to conveniently keep and access test-related options in a ``test`` - subdir and still add command line options. +- early-load "conftest.py" files in non-dot first-level sub directories. + allows to conveniently keep and access test-related options in a ``test`` + subdir and still add command line options. - fix issue67: new super-short traceback-printing option: "--tb=line" will print a single line for each failing (python) test indicating its filename, lineno and the failure value - fix issue78: always call python-level teardown functions even if the - according setup failed. This includes refinements for calling setup_module/class functions + according setup failed. This includes refinements for calling setup_module/class functions which will now only be called once instead of the previous behaviour where they'd be called multiple times if they raise an exception (including a Skipped exception). Any exception will be re-corded and associated with all tests in the according module/class scope. - fix issue63: assume <40 columns to be a bogus terminal width, default to 80 -- fix pdb debugging to be in the correct frame on raises-related errors +- fix pdb debugging to be in the correct frame on raises-related errors - update apipkg.py to fix an issue where recursive imports might - unnecessarily break importing + unnecessarily break importing -- fix plugin links +- fix plugin links Changes between 1.2 and 1.1.1 ===================================== -- moved dist/looponfailing from py.test core into a new +- moved dist/looponfailing from py.test core into a new separately released pytest-xdist plugin. - new junitxml plugin: --junitxml=path will generate a junit style xml file - which is processable e.g. by the Hudson CI system. + which is processable e.g. by the Hudson CI system. - new option: --genscript=path will generate a standalone py.test script - which will not need any libraries installed. thanks to Ralf Schmitt. + which will not need any libraries installed. thanks to Ralf Schmitt. -- new option: --ignore will prevent specified path from collection. - Can be specified multiple times. +- new option: --ignore will prevent specified path from collection. + Can be specified multiple times. -- new option: --confcutdir=dir will make py.test only consider conftest - files that are relative to the specified dir. +- new option: --confcutdir=dir will make py.test only consider conftest + files that are relative to the specified dir. - new funcarg: "pytestconfig" is the pytest config object for access - to command line args and can now be easily used in a test. + to command line args and can now be easily used in a test. - install 'py.test' and `py.which` with a ``-$VERSION`` suffix to - disambiguate between Python3, python2.X, Jython and PyPy installed versions. + disambiguate between Python3, python2.X, Jython and PyPy installed versions. - new "pytestconfig" funcarg allows access to test config object -- new "pytest_report_header" hook can return additional lines - to be displayed at the header of a test run. +- new "pytest_report_header" hook can return additional lines + to be displayed at the header of a test run. - (experimental) allow "py.test path::name1::name2::..." for pointing to a test within a test collection directly. This might eventually - evolve as a full substitute to "-k" specifications. + evolve as a full substitute to "-k" specifications. - streamlined plugin loading: order is now as documented in - customize.html: setuptools, ENV, commandline, conftest. + customize.html: setuptools, ENV, commandline, conftest. also setuptools entry point names are turned to canonical namees ("pytest_*") -- automatically skip tests that need 'capfd' but have no os.dup +- automatically skip tests that need 'capfd' but have no os.dup -- allow pytest_generate_tests to be defined in classes as well +- allow pytest_generate_tests to be defined in classes as well -- deprecate usage of 'disabled' attribute in favour of pytestmark +- deprecate usage of 'disabled' attribute in favour of pytestmark - deprecate definition of Directory, Module, Class and Function nodes in conftest.py files. Use pytest collect hooks instead. @@ -183,28 +183,28 @@ Changes between 1.2 and 1.1.1 change its long command line options to be a bit shorter (see py.test -h). - change: pytest doctest plugin is now enabled by default and has a - new option --doctest-glob to set a pattern for file matches. + new option --doctest-glob to set a pattern for file matches. -- change: remove internal py._* helper vars, only keep py._pydir +- change: remove internal py._* helper vars, only keep py._pydir -- robustify capturing to survive if custom pytest_runtest_setup - code failed and prevented the capturing setup code from running. +- robustify capturing to survive if custom pytest_runtest_setup + code failed and prevented the capturing setup code from running. - make py.test.* helpers provided by default plugins visible early - works transparently both for pydoc and for interactive sessions - which will regularly see e.g. py.test.mark and py.test.importorskip. + which will regularly see e.g. py.test.mark and py.test.importorskip. -- simplify internal plugin manager machinery +- simplify internal plugin manager machinery - simplify internal collection tree by introducing a RootCollector node - fix assert reinterpreation that sees a call containing "keyword=..." -- fix issue66: invoke pytest_sessionstart and pytest_sessionfinish - hooks on slaves during dist-testing, report module/session teardown +- fix issue66: invoke pytest_sessionstart and pytest_sessionfinish + hooks on slaves during dist-testing, report module/session teardown hooks correctly. -- fix issue65: properly handle dist-testing if no - execnet/py lib installed remotely. +- fix issue65: properly handle dist-testing if no + execnet/py lib installed remotely. - skip some install-tests if no execnet is available @@ -214,15 +214,15 @@ Changes between 1.2 and 1.1.1 Changes between 1.1.1 and 1.1.0 ===================================== -- introduce automatic plugin registration via 'pytest11' +- introduce automatic plugin registration via 'pytest11' entrypoints via setuptools' pkg_resources.iter_entry_points -- fix py.test dist-testing to work with execnet >= 1.0.0b4 +- fix py.test dist-testing to work with execnet >= 1.0.0b4 -- re-introduce py.test.cmdline.main() for better backward compatibility +- re-introduce py.test.cmdline.main() for better backward compatibility - svn paths: fix a bug with path.check(versioned=True) for svn paths, - allow '%' in svn paths, make svnwc.update() default to interactive mode + allow '%' in svn paths, make svnwc.update() default to interactive mode like in 1.0.x and add svnwc.update(interactive=False) to inhibit interaction. - refine distributed tarball to contain test and no pyc files @@ -237,16 +237,16 @@ Changes between 1.1.0 and 1.0.2 * remove py.rest tool and internal namespace - it was never really advertised and can still be used with - the old release if needed. If there is interest + the old release if needed. If there is interest it could be revived into its own tool i guess. * fix issue48 and issue59: raise an Error if the module - from an imported test file does not seem to come from + from an imported test file does not seem to come from the filepath - avoids "same-name" confusion that has been reported repeatedly * merged Ronny's nose-compatibility hacks: now - nose-style setup_module() and setup() functions are + nose-style setup_module() and setup() functions are supported * introduce generalized py.test.mark function marking @@ -255,112 +255,112 @@ Changes between 1.1.0 and 1.0.2 * deprecate parser.addgroup in favour of getgroup which creates option group -* add --report command line option that allows to control showing of skipped/xfailed sections +* add --report command line option that allows to control showing of skipped/xfailed sections -* generalized skipping: a new way to mark python functions with skipif or xfail - at function, class and modules level based on platform or sys-module attributes. +* generalized skipping: a new way to mark python functions with skipif or xfail + at function, class and modules level based on platform or sys-module attributes. * extend py.test.mark decorator to allow for positional args -* introduce and test "py.cleanup -d" to remove empty directories +* introduce and test "py.cleanup -d" to remove empty directories * fix issue #59 - robustify unittest test collection -* make bpython/help interaction work by adding an __all__ attribute +* make bpython/help interaction work by adding an __all__ attribute to ApiModule, cleanup initpkg * use MIT license for pylib, add some contributors * remove py.execnet code and substitute all usages with 'execnet' proper -* fix issue50 - cached_setup now caches more to expectations - for test functions with multiple arguments. +* fix issue50 - cached_setup now caches more to expectations + for test functions with multiple arguments. * merge Jarko's fixes, issue #45 and #46 * add the ability to specify a path for py.lookup to search in -* fix a funcarg cached_setup bug probably only occuring - in distributed testing and "module" scope with teardown. +* fix a funcarg cached_setup bug probably only occuring + in distributed testing and "module" scope with teardown. * many fixes and changes for making the code base python3 compatible, - many thanks to Benjamin Peterson for helping with this. + many thanks to Benjamin Peterson for helping with this. -* consolidate builtins implementation to be compatible with >=2.3, +* consolidate builtins implementation to be compatible with >=2.3, add helpers to ease keeping 2 and 3k compatible code * deprecate py.compat.doctest|subprocess|textwrap|optparse -* deprecate py.magic.autopath, remove py/magic directory +* deprecate py.magic.autopath, remove py/magic directory * move pytest assertion handling to py/code and a pytest_assertion - plugin, add "--no-assert" option, deprecate py.magic namespaces - in favour of (less) py.code ones. + plugin, add "--no-assert" option, deprecate py.magic namespaces + in favour of (less) py.code ones. -* consolidate and cleanup py/code classes and files +* consolidate and cleanup py/code classes and files -* cleanup py/misc, move tests to bin-for-dist +* cleanup py/misc, move tests to bin-for-dist -* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg +* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg -* consolidate py.log implementation, remove old approach. +* consolidate py.log implementation, remove old approach. * introduce py.io.TextIO and py.io.BytesIO for distinguishing between - text/unicode and byte-streams (uses underlying standard lib io.* - if available) + text/unicode and byte-streams (uses underlying standard lib io.* + if available) -* make py.unittest_convert helper script available which converts "unittest.py" +* make py.unittest_convert helper script available which converts "unittest.py" style files into the simpler assert/direct-test-classes py.test/nosetests - style. The script was written by Laura Creighton. - -* simplified internal localpath implementation + style. The script was written by Laura Creighton. + +* simplified internal localpath implementation Changes between 1.0.1 and 1.0.2 ===================================== -* fixing packaging issues, triggered by fedora redhat packaging, - also added doc, examples and contrib dirs to the tarball. +* fixing packaging issues, triggered by fedora redhat packaging, + also added doc, examples and contrib dirs to the tarball. -* added a documentation link to the new django plugin. +* added a documentation link to the new django plugin. Changes between 1.0.0 and 1.0.1 ===================================== -* added a 'pytest_nose' plugin which handles nose.SkipTest, - nose-style function/method/generator setup/teardown and - tries to report functions correctly. +* added a 'pytest_nose' plugin which handles nose.SkipTest, + nose-style function/method/generator setup/teardown and + tries to report functions correctly. -* capturing of unicode writes or encoded strings to sys.stdout/err - work better, also terminalwriting was adapted and somewhat - unified between windows and linux. +* capturing of unicode writes or encoded strings to sys.stdout/err + work better, also terminalwriting was adapted and somewhat + unified between windows and linux. * improved documentation layout and content a lot * added a "--help-config" option to show conftest.py / ENV-var names for - all longopt cmdline options, and some special conftest.py variables. - renamed 'conf_capture' conftest setting to 'option_capture' accordingly. + all longopt cmdline options, and some special conftest.py variables. + renamed 'conf_capture' conftest setting to 'option_capture' accordingly. -* fix issue #27: better reporting on non-collectable items given on commandline +* fix issue #27: better reporting on non-collectable items given on commandline (e.g. pyc files) -* fix issue #33: added --version flag (thanks Benjamin Peterson) +* fix issue #33: added --version flag (thanks Benjamin Peterson) * fix issue #32: adding support for "incomplete" paths to wcpath.status() -* "Test" prefixed classes are *not* collected by default anymore if they - have an __init__ method +* "Test" prefixed classes are *not* collected by default anymore if they + have an __init__ method * monkeypatch setenv() now accepts a "prepend" parameter * improved reporting of collection error tracebacks -* simplified multicall mechanism and plugin architecture, - renamed some internal methods and argnames +* simplified multicall mechanism and plugin architecture, + renamed some internal methods and argnames Changes between 1.0.0b9 and 1.0.0 ===================================== -* more terse reporting try to show filesystem path relatively to current dir +* more terse reporting try to show filesystem path relatively to current dir * improve xfail output a bit Changes between 1.0.0b8 and 1.0.0b9 @@ -373,26 +373,26 @@ Changes between 1.0.0b8 and 1.0.0b9 * setup/teardown or collection problems now show as ERRORs or with big "E"'s in the progress lines. they are reported - and counted separately. - -* dist-testing: properly handle test items that get locally - collected but cannot be collected on the remote side - often + and counted separately. + +* dist-testing: properly handle test items that get locally + collected but cannot be collected on the remote side - often due to platform/dependency reasons * simplified py.test.mark API - see keyword plugin documentation * integrate better with logging: capturing now by default captures - test functions and their immediate setup/teardown in a single stream + test functions and their immediate setup/teardown in a single stream * capsys and capfd funcargs now have a readouterr() and a close() method - (underlyingly py.io.StdCapture/FD objects are used which grew a + (underlyingly py.io.StdCapture/FD objects are used which grew a readouterr() method as well to return snapshots of captured out/err) -* make assert-reinterpretation work better with comparisons not +* make assert-reinterpretation work better with comparisons not returning bools (reported with numpy from thanks maciej fijalkowski) -* reworked per-test output capturing into the pytest_iocapture.py plugin - and thus removed capturing code from config object +* reworked per-test output capturing into the pytest_iocapture.py plugin + and thus removed capturing code from config object * item.repr_failure(excinfo) instead of item.repr_failure(excinfo, outerr) @@ -402,126 +402,126 @@ Changes between 1.0.0b7 and 1.0.0b8 * pytest_unittest-plugin is now enabled by default -* introduced pytest_keyboardinterrupt hook and - refined pytest_sessionfinish hooked, added tests. +* introduced pytest_keyboardinterrupt hook and + refined pytest_sessionfinish hooked, added tests. * workaround a buggy logging module interaction ("closing already closed - files"). Thanks to Sridhar Ratnakumar for triggering. + files"). Thanks to Sridhar Ratnakumar for triggering. -* if plugins use "py.test.importorskip" for importing - a dependency only a warning will be issued instead - of exiting the testing process. +* if plugins use "py.test.importorskip" for importing + a dependency only a warning will be issued instead + of exiting the testing process. -* many improvements to docs: +* many improvements to docs: - refined funcargs doc , use the term "factory" instead of "provider" - - added a new talk/tutorial doc page + - added a new talk/tutorial doc page - better download page - better plugin docstrings - added new plugins page and automatic doc generation script -* fixed teardown problem related to partially failing funcarg setups - (thanks MrTopf for reporting), "pytest_runtest_teardown" is now - always invoked even if the "pytest_runtest_setup" failed. +* fixed teardown problem related to partially failing funcarg setups + (thanks MrTopf for reporting), "pytest_runtest_teardown" is now + always invoked even if the "pytest_runtest_setup" failed. -* tweaked doctest output for docstrings in py modules, - thanks Radomir. +* tweaked doctest output for docstrings in py modules, + thanks Radomir. Changes between 1.0.0b3 and 1.0.0b7 ============================================= -* renamed py.test.xfail back to py.test.mark.xfail to avoid +* renamed py.test.xfail back to py.test.mark.xfail to avoid two ways to decorate for xfail -* re-added py.test.mark decorator for setting keywords on functions - (it was actually documented so removing it was not nice) +* re-added py.test.mark decorator for setting keywords on functions + (it was actually documented so removing it was not nice) -* remove scope-argument from request.addfinalizer() because - request.cached_setup has the scope arg. TOOWTDI. +* remove scope-argument from request.addfinalizer() because + request.cached_setup has the scope arg. TOOWTDI. * perform setup finalization before reporting failures -* apply modified patches from Andreas Kloeckner to allow - test functions to have no func_code (#22) and to make - "-k" and function keywords work (#20) +* apply modified patches from Andreas Kloeckner to allow + test functions to have no func_code (#22) and to make + "-k" and function keywords work (#20) -* apply patch from Daniel Peolzleithner (issue #23) +* apply patch from Daniel Peolzleithner (issue #23) -* resolve issue #18, multiprocessing.Manager() and - redirection clash +* resolve issue #18, multiprocessing.Manager() and + redirection clash * make __name__ == "__channelexec__" for remote_exec code Changes between 1.0.0b1 and 1.0.0b3 ============================================= -* plugin classes are removed: one now defines - hooks directly in conftest.py or global pytest_*.py - files. +* plugin classes are removed: one now defines + hooks directly in conftest.py or global pytest_*.py + files. -* added new pytest_namespace(config) hook that allows - to inject helpers directly to the py.test.* namespace. +* added new pytest_namespace(config) hook that allows + to inject helpers directly to the py.test.* namespace. -* documented and refined many hooks +* documented and refined many hooks + +* added new style of generative tests via + pytest_generate_tests hook that integrates + well with function arguments. -* added new style of generative tests via - pytest_generate_tests hook that integrates - well with function arguments. - Changes between 0.9.2 and 1.0.0b1 ============================================= -* introduced new "funcarg" setup method, - see doc/test/funcarg.txt +* introduced new "funcarg" setup method, + see doc/test/funcarg.txt -* introduced plugin architecuture and many - new py.test plugins, see +* introduced plugin architecuture and many + new py.test plugins, see doc/test/plugins.txt -* teardown_method is now guaranteed to get - called after a test method has run. - +* teardown_method is now guaranteed to get + called after a test method has run. + * new method: py.test.importorskip(mod,minversion) will either import or call py.test.skip() * completely revised internal py.test architecture -* new py.process.ForkedFunc object allowing to +* new py.process.ForkedFunc object allowing to fork execution of a function to a sub process - and getting a result back. + and getting a result back. XXX lots of things missing here XXX Changes between 0.9.1 and 0.9.2 =============================== -* refined installation and metadata, created new setup.py, - now based on setuptools/ez_setup (thanks to Ralf Schmitt +* refined installation and metadata, created new setup.py, + now based on setuptools/ez_setup (thanks to Ralf Schmitt for his support). -* improved the way of making py.* scripts available in - windows environments, they are now added to the - Scripts directory as ".cmd" files. +* improved the way of making py.* scripts available in + windows environments, they are now added to the + Scripts directory as ".cmd" files. -* py.path.svnwc.status() now is more complete and +* py.path.svnwc.status() now is more complete and uses xml output from the 'svn' command if available (Guido Wesdorp) * fix for py.path.svn* to work with svn 1.5 (Chris Lamb) -* fix path.relto(otherpath) method on windows to +* fix path.relto(otherpath) method on windows to use normcase for checking if a path is relative. -* py.test's traceback is better parseable from editors +* py.test's traceback is better parseable from editors (follows the filenames:LINENO: MSG convention) (thanks to Osmo Salomaa) -* fix to javascript-generation, "py.test --runbrowser" +* fix to javascript-generation, "py.test --runbrowser" should work more reliably now -* removed previously accidentally added - py.test.broken and py.test.notimplemented helpers. +* removed previously accidentally added + py.test.broken and py.test.notimplemented helpers. * there now is a py.__version__ attribute diff --git a/doc/announce/release-1.3.1.txt b/doc/announce/release-1.3.1.txt index 151e75e05..471de408a 100644 --- a/doc/announce/release-1.3.1.txt +++ b/doc/announce/release-1.3.1.txt @@ -1,21 +1,21 @@ py.test/pylib 1.3.1: new py.test.xfail, --maxfail, better reporting =========================================================================== -The pylib/py.test 1.3.1 release brings: +The pylib/py.test 1.3.1 release brings: -- the new imperative ``py.test.xfail()`` helper in order to have a test or +- the new imperative ``py.test.xfail()`` helper in order to have a test or setup function result in an "expected failure" - a new option ``--maxfail=NUM`` to stop the test run after some failures - markers/decorators are now applicable to test classes (>=Python2.6) - improved reporting, shorter tracebacks in several cases -- some simplified internals, more compatibility with Jython and PyPy +- some simplified internals, more compatibility with Jython and PyPy - bug fixes and various refinements See the below CHANGELOG entry below for more details and -http://pylib.org/install.html for installation instructions. +http://pylib.org/install.html for installation instructions. -If you used older versions of py.test you should be able to upgrade -to 1.3.1 without changes to your test source code. +If you used older versions of py.test you should be able to upgrade +to 1.3.1 without changes to your test source code. py.test is an automated testing tool working with Python2, Python3, Jython and PyPy versions on all major operating systems. It @@ -23,7 +23,7 @@ offers a no-boilerplate testing approach and has inspired other testing tools and enhancements in the standard Python library for more than five years. It has a simple and extensive plugin architecture, configurable reporting and provides unique ways to make it fit to your testing -process and needs. +process and needs. See http://pytest.org for more info. @@ -34,27 +34,27 @@ holger krekel Changes between 1.3.0 and 1.3.1 ================================================== -New features +New features ++++++++++++++++++ -- issue91: introduce new py.test.xfail(reason) helper - to imperatively mark a test as expected to fail. Can +- issue91: introduce new py.test.xfail(reason) helper + to imperatively mark a test as expected to fail. Can be used from within setup and test functions. This is - useful especially for parametrized tests when certain + useful especially for parametrized tests when certain configurations are expected-to-fail. In this case the declarative approach with the @py.test.mark.xfail cannot - be used as it would mark all configurations as xfail. + be used as it would mark all configurations as xfail. - issue102: introduce new --maxfail=NUM option to stop test runs after NUM failures. This is a generalization of the '-x' or '--exitfirst' option which is now equivalent - to '--maxfail=1'. Both '-x' and '--maxfail' will - now also print a line near the end indicating the Interruption. + to '--maxfail=1'. Both '-x' and '--maxfail' will + now also print a line near the end indicating the Interruption. - issue89: allow py.test.mark decorators to be used on classes - (class decorators were introduced with python2.6) and + (class decorators were introduced with python2.6) and also allow to have multiple markers applied at class/module level - by specifying a list. + by specifying a list. - improve and refine letter reporting in the progress bar: . pass @@ -64,19 +64,19 @@ New features X xpassed test (test that was expected to fail but passed) You can use any combination of 'fsxX' with the '-r' extended - reporting option. The xfail/xpass results will show up as - skipped tests in the junitxml output - which also fixes + reporting option. The xfail/xpass results will show up as + skipped tests in the junitxml output - which also fixes issue99. -- make py.test.cmdline.main() return the exitstatus instead of raising +- make py.test.cmdline.main() return the exitstatus instead of raising SystemExit and also allow it to be called multiple times. This of - course requires that your application and tests are properly teared - down and don't have global state. + course requires that your application and tests are properly teared + down and don't have global state. -Fixes / Maintenance +Fixes / Maintenance ++++++++++++++++++++++ -- improved traceback presentation: +- improved traceback presentation: - improved and unified reporting for "--tb=short" option - Errors during test module imports are much shorter, (using --tb=short style) - raises shows shorter more relevant tracebacks @@ -84,20 +84,20 @@ Fixes / Maintenance - improve support for raises and other dynamically compiled code by manipulating python's linecache.cache instead of the previous - rather hacky way of creating custom code objects. This makes + rather hacky way of creating custom code objects. This makes it seemlessly work on Jython and PyPy where it previously didn't. -- fix issue96: make capturing more resilient against Control-C +- fix issue96: make capturing more resilient against Control-C interruptions (involved somewhat substantial refactoring - to the underlying capturing functionality to avoid race + to the underlying capturing functionality to avoid race conditions). -- fix chaining of conditional skipif/xfail decorators - so it works now +- fix chaining of conditional skipif/xfail decorators - so it works now as expected to use multiple @py.test.mark.skipif(condition) decorators, - including specific reporting which of the conditions lead to skipping. + including specific reporting which of the conditions lead to skipping. -- fix issue95: late-import zlib so that it's not required - for general py.test startup. +- fix issue95: late-import zlib so that it's not required + for general py.test startup. - fix issue94: make reporting more robust against bogus source code (and internally be more careful when presenting unexpected byte sequences) diff --git a/doc/announce/release-1.3.2.txt b/doc/announce/release-1.3.2.txt index 6c1642aa6..599dfbed7 100644 --- a/doc/announce/release-1.3.2.txt +++ b/doc/announce/release-1.3.2.txt @@ -1,4 +1,4 @@ -py.test/pylib 1.3.2: API and reporting refinements, many fixes +py.test/pylib 1.3.2: API and reporting refinements, many fixes =========================================================================== The pylib/py.test 1.3.2 release brings many bug fixes and some new @@ -6,25 +6,25 @@ features. It was refined for and tested against the recently released Python2.7 and remains compatibile to the usual armada of interpreters (Python2.4 through to Python3.1.2, Jython and PyPy). Note that for using distributed testing features you'll need to upgrade to the jointly released -pytest-xdist-1.4 because of some internal refactorings. +pytest-xdist-1.4 because of some internal refactorings. -See http://pytest.org for general documentation and below for -a detailed CHANGELOG. +See http://pytest.org for general documentation and below for +a detailed CHANGELOG. -cheers & particular thanks to Benjamin Peterson, Ronny Pfannschmidt -and all issue and patch contributors, +cheers & particular thanks to Benjamin Peterson, Ronny Pfannschmidt +and all issue and patch contributors, holger krekel Changes between 1.3.1 and 1.3.2 ================================================== -New features +New features ++++++++++++++++++ - fix issue103: introduce py.test.raises as context manager, examples:: - with py.test.raises(ZeroDivisionError): + with py.test.raises(ZeroDivisionError): x = 0 1 / x @@ -33,10 +33,10 @@ New features # you may do extra checks on excinfo.value|type|traceback here - (thanks Ronny Pfannschmidt) + (thanks Ronny Pfannschmidt) -- Funcarg factories can now dynamically apply a marker to a - test invocation. This is for example useful if a factory +- Funcarg factories can now dynamically apply a marker to a + test invocation. This is for example useful if a factory provides parameters to a test which are expected-to-fail:: def pytest_funcarg__arg(request): @@ -46,75 +46,75 @@ New features def test_function(arg): ... -- improved error reporting on collection and import errors. This makes +- improved error reporting on collection and import errors. This makes use of a more general mechanism, namely that for custom test item/collect - nodes ``node.repr_failure(excinfo)`` is now uniformly called so that you can - override it to return a string error representation of your choice - which is going to be reported as a (red) string. + nodes ``node.repr_failure(excinfo)`` is now uniformly called so that you can + override it to return a string error representation of your choice + which is going to be reported as a (red) string. -- introduce '--junitprefix=STR' option to prepend a prefix - to all reports in the junitxml file. +- introduce '--junitprefix=STR' option to prepend a prefix + to all reports in the junitxml file. Bug fixes / Maintenance ++++++++++++++++++++++++++ -- make tests and the ``pytest_recwarn`` plugin in particular fully compatible - to Python2.7 (if you use the ``recwarn`` funcarg warnings will be enabled so that - you can properly check for their existence in a cross-python manner). -- refine --pdb: ignore xfailed tests, unify its TB-reporting and +- make tests and the ``pytest_recwarn`` plugin in particular fully compatible + to Python2.7 (if you use the ``recwarn`` funcarg warnings will be enabled so that + you can properly check for their existence in a cross-python manner). +- refine --pdb: ignore xfailed tests, unify its TB-reporting and don't display failures again at the end. - fix assertion interpretation with the ** operator (thanks Benjamin Peterson) - fix issue105 assignment on the same line as a failing assertion (thanks Benjamin Peterson) - fix issue104 proper escaping for test names in junitxml plugin (thanks anonymous) - fix issue57 -f|--looponfail to work with xpassing tests (thanks Ronny) - fix issue92 collectonly reporter and --pastebin (thanks Benjamin Peterson) -- fix py.code.compile(source) to generate unique filenames -- fix assertion re-interp problems on PyPy, by defering code +- fix py.code.compile(source) to generate unique filenames +- fix assertion re-interp problems on PyPy, by defering code compilation to the (overridable) Frame.eval class. (thanks Amaury Forgeot) - fix py.path.local.pyimport() to work with directories - streamline py.path.local.mkdtemp implementation and usage - don't print empty lines when showing junitxml-filename - add optional boolean ignore_errors parameter to py.path.local.remove -- fix terminal writing on win32/python2.4 -- py.process.cmdexec() now tries harder to return properly encoded unicode objects +- fix terminal writing on win32/python2.4 +- py.process.cmdexec() now tries harder to return properly encoded unicode objects on all python versions - install plain py.test/py.which scripts also for Jython, this helps to get canonical script paths in virtualenv situations -- make path.bestrelpath(path) return ".", note that when calling - X.bestrelpath the assumption is that X is a directory. -- make initial conftest discovery ignore "--" prefixed arguments -- fix resultlog plugin when used in an multicpu/multihost xdist situation - (thanks Jakub Gustak) -- perform distributed testing related reporting in the xdist-plugin - rather than having dist-related code in the generic py.test +- make path.bestrelpath(path) return ".", note that when calling + X.bestrelpath the assumption is that X is a directory. +- make initial conftest discovery ignore "--" prefixed arguments +- fix resultlog plugin when used in an multicpu/multihost xdist situation + (thanks Jakub Gustak) +- perform distributed testing related reporting in the xdist-plugin + rather than having dist-related code in the generic py.test distribution -- fix homedir detection on Windows +- fix homedir detection on Windows - ship distribute_setup.py version 0.6.13 Changes between 1.3.0 and 1.3.1 ================================================== -New features +New features ++++++++++++++++++ -- issue91: introduce new py.test.xfail(reason) helper - to imperatively mark a test as expected to fail. Can +- issue91: introduce new py.test.xfail(reason) helper + to imperatively mark a test as expected to fail. Can be used from within setup and test functions. This is - useful especially for parametrized tests when certain + useful especially for parametrized tests when certain configurations are expected-to-fail. In this case the declarative approach with the @py.test.mark.xfail cannot - be used as it would mark all configurations as xfail. + be used as it would mark all configurations as xfail. - issue102: introduce new --maxfail=NUM option to stop test runs after NUM failures. This is a generalization of the '-x' or '--exitfirst' option which is now equivalent - to '--maxfail=1'. Both '-x' and '--maxfail' will - now also print a line near the end indicating the Interruption. + to '--maxfail=1'. Both '-x' and '--maxfail' will + now also print a line near the end indicating the Interruption. - issue89: allow py.test.mark decorators to be used on classes - (class decorators were introduced with python2.6) and + (class decorators were introduced with python2.6) and also allow to have multiple markers applied at class/module level - by specifying a list. + by specifying a list. - improve and refine letter reporting in the progress bar: . pass @@ -124,19 +124,19 @@ New features X xpassed test (test that was expected to fail but passed) You can use any combination of 'fsxX' with the '-r' extended - reporting option. The xfail/xpass results will show up as - skipped tests in the junitxml output - which also fixes + reporting option. The xfail/xpass results will show up as + skipped tests in the junitxml output - which also fixes issue99. -- make py.test.cmdline.main() return the exitstatus instead of raising +- make py.test.cmdline.main() return the exitstatus instead of raising SystemExit and also allow it to be called multiple times. This of - course requires that your application and tests are properly teared - down and don't have global state. + course requires that your application and tests are properly teared + down and don't have global state. -Fixes / Maintenance +Fixes / Maintenance ++++++++++++++++++++++ -- improved traceback presentation: +- improved traceback presentation: - improved and unified reporting for "--tb=short" option - Errors during test module imports are much shorter, (using --tb=short style) - raises shows shorter more relevant tracebacks @@ -144,20 +144,20 @@ Fixes / Maintenance - improve support for raises and other dynamically compiled code by manipulating python's linecache.cache instead of the previous - rather hacky way of creating custom code objects. This makes + rather hacky way of creating custom code objects. This makes it seemlessly work on Jython and PyPy where it previously didn't. -- fix issue96: make capturing more resilient against Control-C +- fix issue96: make capturing more resilient against Control-C interruptions (involved somewhat substantial refactoring - to the underlying capturing functionality to avoid race + to the underlying capturing functionality to avoid race conditions). -- fix chaining of conditional skipif/xfail decorators - so it works now +- fix chaining of conditional skipif/xfail decorators - so it works now as expected to use multiple @py.test.mark.skipif(condition) decorators, - including specific reporting which of the conditions lead to skipping. + including specific reporting which of the conditions lead to skipping. -- fix issue95: late-import zlib so that it's not required - for general py.test startup. +- fix issue95: late-import zlib so that it's not required + for general py.test startup. - fix issue94: make reporting more robust against bogus source code (and internally be more careful when presenting unexpected byte sequences) @@ -169,40 +169,40 @@ Changes between 1.2.1 and 1.3.0 - deprecate --report option in favour of a new shorter and easier to remember -r option: it takes a string argument consisting of any combination of 'xfsX' characters. They relate to the single chars - you see during the dotted progress printing and will print an extra line + you see during the dotted progress printing and will print an extra line per test at the end of the test run. This extra line indicates the exact position or test ID that you directly paste to the py.test cmdline in order - to re-run a particular test. + to re-run a particular test. -- allow external plugins to register new hooks via the new +- allow external plugins to register new hooks via the new pytest_addhooks(pluginmanager) hook. The new release of - the pytest-xdist plugin for distributed and looponfailing - testing requires this feature. + the pytest-xdist plugin for distributed and looponfailing + testing requires this feature. - add a new pytest_ignore_collect(path, config) hook to allow projects and - plugins to define exclusion behaviour for their directory structure - + plugins to define exclusion behaviour for their directory structure - for example you may define in a conftest.py this method:: def pytest_ignore_collect(path): return path.check(link=1) - to prevent even a collection try of any tests in symlinked dirs. + to prevent even a collection try of any tests in symlinked dirs. - new pytest_pycollect_makemodule(path, parent) hook for - allowing customization of the Module collection object for a - matching test module. + allowing customization of the Module collection object for a + matching test module. -- extend and refine xfail mechanism: +- extend and refine xfail mechanism: ``@py.test.mark.xfail(run=False)`` do not run the decorated test ``@py.test.mark.xfail(reason="...")`` prints the reason string in xfail summaries specifiying ``--runxfail`` on command line virtually ignores xfail markers -- expose (previously internal) commonly useful methods: +- expose (previously internal) commonly useful methods: py.io.get_terminal_with() -> return terminal width py.io.ansi_print(...) -> print colored/bold text on linux/win32 py.io.saferepr(obj) -> return limited representation string -- expose test outcome related exceptions as py.test.skip.Exception, +- expose test outcome related exceptions as py.test.skip.Exception, py.test.raises.Exception etc., useful mostly for plugins doing special outcome interpretation/tweaking @@ -210,22 +210,22 @@ Changes between 1.2.1 and 1.3.0 - fix/refine python3 compatibility (thanks Benjamin Peterson) -- fixes for making the jython/win32 combination work, note however: +- fixes for making the jython/win32 combination work, note however: jython2.5.1/win32 does not provide a command line launcher, see http://bugs.jython.org/issue1491 . See pylib install documentation - for how to work around. + for how to work around. - fixes for handling of unicode exception values and unprintable objects -- (issue87) fix unboundlocal error in assertionold code +- (issue87) fix unboundlocal error in assertionold code - (issue86) improve documentation for looponfailing - refine IO capturing: stdin-redirect pseudo-file now has a NOP close() method -- ship distribute_setup.py version 0.6.10 +- ship distribute_setup.py version 0.6.10 -- added links to the new capturelog and coverage plugins +- added links to the new capturelog and coverage plugins Changes between 1.2.1 and 1.2.0 @@ -236,79 +236,79 @@ Changes between 1.2.1 and 1.2.0 py.cleanup # remove "*.pyc" and "*$py.class" (jython) files py.cleanup -e .swp -e .cache # also remove files with these extensions py.cleanup -s # remove "build" and "dist" directory next to setup.py files - py.cleanup -d # also remove empty directories + py.cleanup -d # also remove empty directories py.cleanup -a # synonym for "-s -d -e 'pip-log.txt'" py.cleanup -n # dry run, only show what would be removed -- add a new option "py.test --funcargs" which shows available funcargs - and their help strings (docstrings on their respective factory function) +- add a new option "py.test --funcargs" which shows available funcargs + and their help strings (docstrings on their respective factory function) for a given test path -- display a short and concise traceback if a funcarg lookup fails +- display a short and concise traceback if a funcarg lookup fails -- early-load "conftest.py" files in non-dot first-level sub directories. - allows to conveniently keep and access test-related options in a ``test`` - subdir and still add command line options. +- early-load "conftest.py" files in non-dot first-level sub directories. + allows to conveniently keep and access test-related options in a ``test`` + subdir and still add command line options. - fix issue67: new super-short traceback-printing option: "--tb=line" will print a single line for each failing (python) test indicating its filename, lineno and the failure value - fix issue78: always call python-level teardown functions even if the - according setup failed. This includes refinements for calling setup_module/class functions + according setup failed. This includes refinements for calling setup_module/class functions which will now only be called once instead of the previous behaviour where they'd be called multiple times if they raise an exception (including a Skipped exception). Any exception will be re-corded and associated with all tests in the according module/class scope. - fix issue63: assume <40 columns to be a bogus terminal width, default to 80 -- fix pdb debugging to be in the correct frame on raises-related errors +- fix pdb debugging to be in the correct frame on raises-related errors - update apipkg.py to fix an issue where recursive imports might - unnecessarily break importing + unnecessarily break importing -- fix plugin links +- fix plugin links Changes between 1.2 and 1.1.1 ===================================== -- moved dist/looponfailing from py.test core into a new +- moved dist/looponfailing from py.test core into a new separately released pytest-xdist plugin. - new junitxml plugin: --junitxml=path will generate a junit style xml file - which is processable e.g. by the Hudson CI system. + which is processable e.g. by the Hudson CI system. - new option: --genscript=path will generate a standalone py.test script - which will not need any libraries installed. thanks to Ralf Schmitt. + which will not need any libraries installed. thanks to Ralf Schmitt. -- new option: --ignore will prevent specified path from collection. - Can be specified multiple times. +- new option: --ignore will prevent specified path from collection. + Can be specified multiple times. -- new option: --confcutdir=dir will make py.test only consider conftest - files that are relative to the specified dir. +- new option: --confcutdir=dir will make py.test only consider conftest + files that are relative to the specified dir. - new funcarg: "pytestconfig" is the pytest config object for access - to command line args and can now be easily used in a test. + to command line args and can now be easily used in a test. - install 'py.test' and `py.which` with a ``-$VERSION`` suffix to - disambiguate between Python3, python2.X, Jython and PyPy installed versions. + disambiguate between Python3, python2.X, Jython and PyPy installed versions. - new "pytestconfig" funcarg allows access to test config object -- new "pytest_report_header" hook can return additional lines - to be displayed at the header of a test run. +- new "pytest_report_header" hook can return additional lines + to be displayed at the header of a test run. - (experimental) allow "py.test path::name1::name2::..." for pointing to a test within a test collection directly. This might eventually - evolve as a full substitute to "-k" specifications. + evolve as a full substitute to "-k" specifications. - streamlined plugin loading: order is now as documented in - customize.html: setuptools, ENV, commandline, conftest. + customize.html: setuptools, ENV, commandline, conftest. also setuptools entry point names are turned to canonical namees ("pytest_*") -- automatically skip tests that need 'capfd' but have no os.dup +- automatically skip tests that need 'capfd' but have no os.dup -- allow pytest_generate_tests to be defined in classes as well +- allow pytest_generate_tests to be defined in classes as well -- deprecate usage of 'disabled' attribute in favour of pytestmark +- deprecate usage of 'disabled' attribute in favour of pytestmark - deprecate definition of Directory, Module, Class and Function nodes in conftest.py files. Use pytest collect hooks instead. @@ -323,28 +323,28 @@ Changes between 1.2 and 1.1.1 change its long command line options to be a bit shorter (see py.test -h). - change: pytest doctest plugin is now enabled by default and has a - new option --doctest-glob to set a pattern for file matches. + new option --doctest-glob to set a pattern for file matches. -- change: remove internal py._* helper vars, only keep py._pydir +- change: remove internal py._* helper vars, only keep py._pydir -- robustify capturing to survive if custom pytest_runtest_setup - code failed and prevented the capturing setup code from running. +- robustify capturing to survive if custom pytest_runtest_setup + code failed and prevented the capturing setup code from running. - make py.test.* helpers provided by default plugins visible early - works transparently both for pydoc and for interactive sessions - which will regularly see e.g. py.test.mark and py.test.importorskip. + which will regularly see e.g. py.test.mark and py.test.importorskip. -- simplify internal plugin manager machinery +- simplify internal plugin manager machinery - simplify internal collection tree by introducing a RootCollector node - fix assert reinterpreation that sees a call containing "keyword=..." -- fix issue66: invoke pytest_sessionstart and pytest_sessionfinish - hooks on slaves during dist-testing, report module/session teardown +- fix issue66: invoke pytest_sessionstart and pytest_sessionfinish + hooks on slaves during dist-testing, report module/session teardown hooks correctly. -- fix issue65: properly handle dist-testing if no - execnet/py lib installed remotely. +- fix issue65: properly handle dist-testing if no + execnet/py lib installed remotely. - skip some install-tests if no execnet is available @@ -354,15 +354,15 @@ Changes between 1.2 and 1.1.1 Changes between 1.1.1 and 1.1.0 ===================================== -- introduce automatic plugin registration via 'pytest11' +- introduce automatic plugin registration via 'pytest11' entrypoints via setuptools' pkg_resources.iter_entry_points -- fix py.test dist-testing to work with execnet >= 1.0.0b4 +- fix py.test dist-testing to work with execnet >= 1.0.0b4 -- re-introduce py.test.cmdline.main() for better backward compatibility +- re-introduce py.test.cmdline.main() for better backward compatibility - svn paths: fix a bug with path.check(versioned=True) for svn paths, - allow '%' in svn paths, make svnwc.update() default to interactive mode + allow '%' in svn paths, make svnwc.update() default to interactive mode like in 1.0.x and add svnwc.update(interactive=False) to inhibit interaction. - refine distributed tarball to contain test and no pyc files @@ -377,16 +377,16 @@ Changes between 1.1.0 and 1.0.2 * remove py.rest tool and internal namespace - it was never really advertised and can still be used with - the old release if needed. If there is interest + the old release if needed. If there is interest it could be revived into its own tool i guess. * fix issue48 and issue59: raise an Error if the module - from an imported test file does not seem to come from + from an imported test file does not seem to come from the filepath - avoids "same-name" confusion that has been reported repeatedly * merged Ronny's nose-compatibility hacks: now - nose-style setup_module() and setup() functions are + nose-style setup_module() and setup() functions are supported * introduce generalized py.test.mark function marking @@ -395,112 +395,112 @@ Changes between 1.1.0 and 1.0.2 * deprecate parser.addgroup in favour of getgroup which creates option group -* add --report command line option that allows to control showing of skipped/xfailed sections +* add --report command line option that allows to control showing of skipped/xfailed sections -* generalized skipping: a new way to mark python functions with skipif or xfail - at function, class and modules level based on platform or sys-module attributes. +* generalized skipping: a new way to mark python functions with skipif or xfail + at function, class and modules level based on platform or sys-module attributes. * extend py.test.mark decorator to allow for positional args -* introduce and test "py.cleanup -d" to remove empty directories +* introduce and test "py.cleanup -d" to remove empty directories * fix issue #59 - robustify unittest test collection -* make bpython/help interaction work by adding an __all__ attribute +* make bpython/help interaction work by adding an __all__ attribute to ApiModule, cleanup initpkg * use MIT license for pylib, add some contributors * remove py.execnet code and substitute all usages with 'execnet' proper -* fix issue50 - cached_setup now caches more to expectations - for test functions with multiple arguments. +* fix issue50 - cached_setup now caches more to expectations + for test functions with multiple arguments. * merge Jarko's fixes, issue #45 and #46 * add the ability to specify a path for py.lookup to search in -* fix a funcarg cached_setup bug probably only occuring - in distributed testing and "module" scope with teardown. +* fix a funcarg cached_setup bug probably only occuring + in distributed testing and "module" scope with teardown. * many fixes and changes for making the code base python3 compatible, - many thanks to Benjamin Peterson for helping with this. + many thanks to Benjamin Peterson for helping with this. -* consolidate builtins implementation to be compatible with >=2.3, +* consolidate builtins implementation to be compatible with >=2.3, add helpers to ease keeping 2 and 3k compatible code * deprecate py.compat.doctest|subprocess|textwrap|optparse -* deprecate py.magic.autopath, remove py/magic directory +* deprecate py.magic.autopath, remove py/magic directory * move pytest assertion handling to py/code and a pytest_assertion - plugin, add "--no-assert" option, deprecate py.magic namespaces - in favour of (less) py.code ones. + plugin, add "--no-assert" option, deprecate py.magic namespaces + in favour of (less) py.code ones. -* consolidate and cleanup py/code classes and files +* consolidate and cleanup py/code classes and files -* cleanup py/misc, move tests to bin-for-dist +* cleanup py/misc, move tests to bin-for-dist -* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg +* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg -* consolidate py.log implementation, remove old approach. +* consolidate py.log implementation, remove old approach. * introduce py.io.TextIO and py.io.BytesIO for distinguishing between - text/unicode and byte-streams (uses underlying standard lib io.* - if available) + text/unicode and byte-streams (uses underlying standard lib io.* + if available) -* make py.unittest_convert helper script available which converts "unittest.py" +* make py.unittest_convert helper script available which converts "unittest.py" style files into the simpler assert/direct-test-classes py.test/nosetests - style. The script was written by Laura Creighton. - -* simplified internal localpath implementation + style. The script was written by Laura Creighton. + +* simplified internal localpath implementation Changes between 1.0.1 and 1.0.2 ===================================== -* fixing packaging issues, triggered by fedora redhat packaging, - also added doc, examples and contrib dirs to the tarball. +* fixing packaging issues, triggered by fedora redhat packaging, + also added doc, examples and contrib dirs to the tarball. -* added a documentation link to the new django plugin. +* added a documentation link to the new django plugin. Changes between 1.0.0 and 1.0.1 ===================================== -* added a 'pytest_nose' plugin which handles nose.SkipTest, - nose-style function/method/generator setup/teardown and - tries to report functions correctly. +* added a 'pytest_nose' plugin which handles nose.SkipTest, + nose-style function/method/generator setup/teardown and + tries to report functions correctly. -* capturing of unicode writes or encoded strings to sys.stdout/err - work better, also terminalwriting was adapted and somewhat - unified between windows and linux. +* capturing of unicode writes or encoded strings to sys.stdout/err + work better, also terminalwriting was adapted and somewhat + unified between windows and linux. * improved documentation layout and content a lot * added a "--help-config" option to show conftest.py / ENV-var names for - all longopt cmdline options, and some special conftest.py variables. - renamed 'conf_capture' conftest setting to 'option_capture' accordingly. + all longopt cmdline options, and some special conftest.py variables. + renamed 'conf_capture' conftest setting to 'option_capture' accordingly. -* fix issue #27: better reporting on non-collectable items given on commandline +* fix issue #27: better reporting on non-collectable items given on commandline (e.g. pyc files) -* fix issue #33: added --version flag (thanks Benjamin Peterson) +* fix issue #33: added --version flag (thanks Benjamin Peterson) * fix issue #32: adding support for "incomplete" paths to wcpath.status() -* "Test" prefixed classes are *not* collected by default anymore if they - have an __init__ method +* "Test" prefixed classes are *not* collected by default anymore if they + have an __init__ method * monkeypatch setenv() now accepts a "prepend" parameter * improved reporting of collection error tracebacks -* simplified multicall mechanism and plugin architecture, - renamed some internal methods and argnames +* simplified multicall mechanism and plugin architecture, + renamed some internal methods and argnames Changes between 1.0.0b9 and 1.0.0 ===================================== -* more terse reporting try to show filesystem path relatively to current dir +* more terse reporting try to show filesystem path relatively to current dir * improve xfail output a bit Changes between 1.0.0b8 and 1.0.0b9 @@ -513,26 +513,26 @@ Changes between 1.0.0b8 and 1.0.0b9 * setup/teardown or collection problems now show as ERRORs or with big "E"'s in the progress lines. they are reported - and counted separately. - -* dist-testing: properly handle test items that get locally - collected but cannot be collected on the remote side - often + and counted separately. + +* dist-testing: properly handle test items that get locally + collected but cannot be collected on the remote side - often due to platform/dependency reasons * simplified py.test.mark API - see keyword plugin documentation * integrate better with logging: capturing now by default captures - test functions and their immediate setup/teardown in a single stream + test functions and their immediate setup/teardown in a single stream * capsys and capfd funcargs now have a readouterr() and a close() method - (underlyingly py.io.StdCapture/FD objects are used which grew a + (underlyingly py.io.StdCapture/FD objects are used which grew a readouterr() method as well to return snapshots of captured out/err) -* make assert-reinterpretation work better with comparisons not +* make assert-reinterpretation work better with comparisons not returning bools (reported with numpy from thanks maciej fijalkowski) -* reworked per-test output capturing into the pytest_iocapture.py plugin - and thus removed capturing code from config object +* reworked per-test output capturing into the pytest_iocapture.py plugin + and thus removed capturing code from config object * item.repr_failure(excinfo) instead of item.repr_failure(excinfo, outerr) @@ -542,126 +542,126 @@ Changes between 1.0.0b7 and 1.0.0b8 * pytest_unittest-plugin is now enabled by default -* introduced pytest_keyboardinterrupt hook and - refined pytest_sessionfinish hooked, added tests. +* introduced pytest_keyboardinterrupt hook and + refined pytest_sessionfinish hooked, added tests. * workaround a buggy logging module interaction ("closing already closed - files"). Thanks to Sridhar Ratnakumar for triggering. + files"). Thanks to Sridhar Ratnakumar for triggering. -* if plugins use "py.test.importorskip" for importing - a dependency only a warning will be issued instead - of exiting the testing process. +* if plugins use "py.test.importorskip" for importing + a dependency only a warning will be issued instead + of exiting the testing process. -* many improvements to docs: +* many improvements to docs: - refined funcargs doc , use the term "factory" instead of "provider" - - added a new talk/tutorial doc page + - added a new talk/tutorial doc page - better download page - better plugin docstrings - added new plugins page and automatic doc generation script -* fixed teardown problem related to partially failing funcarg setups - (thanks MrTopf for reporting), "pytest_runtest_teardown" is now - always invoked even if the "pytest_runtest_setup" failed. +* fixed teardown problem related to partially failing funcarg setups + (thanks MrTopf for reporting), "pytest_runtest_teardown" is now + always invoked even if the "pytest_runtest_setup" failed. -* tweaked doctest output for docstrings in py modules, - thanks Radomir. +* tweaked doctest output for docstrings in py modules, + thanks Radomir. Changes between 1.0.0b3 and 1.0.0b7 ============================================= -* renamed py.test.xfail back to py.test.mark.xfail to avoid +* renamed py.test.xfail back to py.test.mark.xfail to avoid two ways to decorate for xfail -* re-added py.test.mark decorator for setting keywords on functions - (it was actually documented so removing it was not nice) +* re-added py.test.mark decorator for setting keywords on functions + (it was actually documented so removing it was not nice) -* remove scope-argument from request.addfinalizer() because - request.cached_setup has the scope arg. TOOWTDI. +* remove scope-argument from request.addfinalizer() because + request.cached_setup has the scope arg. TOOWTDI. * perform setup finalization before reporting failures -* apply modified patches from Andreas Kloeckner to allow - test functions to have no func_code (#22) and to make - "-k" and function keywords work (#20) +* apply modified patches from Andreas Kloeckner to allow + test functions to have no func_code (#22) and to make + "-k" and function keywords work (#20) -* apply patch from Daniel Peolzleithner (issue #23) +* apply patch from Daniel Peolzleithner (issue #23) -* resolve issue #18, multiprocessing.Manager() and - redirection clash +* resolve issue #18, multiprocessing.Manager() and + redirection clash * make __name__ == "__channelexec__" for remote_exec code Changes between 1.0.0b1 and 1.0.0b3 ============================================= -* plugin classes are removed: one now defines - hooks directly in conftest.py or global pytest_*.py - files. +* plugin classes are removed: one now defines + hooks directly in conftest.py or global pytest_*.py + files. -* added new pytest_namespace(config) hook that allows - to inject helpers directly to the py.test.* namespace. +* added new pytest_namespace(config) hook that allows + to inject helpers directly to the py.test.* namespace. -* documented and refined many hooks +* documented and refined many hooks + +* added new style of generative tests via + pytest_generate_tests hook that integrates + well with function arguments. -* added new style of generative tests via - pytest_generate_tests hook that integrates - well with function arguments. - Changes between 0.9.2 and 1.0.0b1 ============================================= -* introduced new "funcarg" setup method, - see doc/test/funcarg.txt +* introduced new "funcarg" setup method, + see doc/test/funcarg.txt -* introduced plugin architecuture and many - new py.test plugins, see +* introduced plugin architecuture and many + new py.test plugins, see doc/test/plugins.txt -* teardown_method is now guaranteed to get - called after a test method has run. - +* teardown_method is now guaranteed to get + called after a test method has run. + * new method: py.test.importorskip(mod,minversion) will either import or call py.test.skip() * completely revised internal py.test architecture -* new py.process.ForkedFunc object allowing to +* new py.process.ForkedFunc object allowing to fork execution of a function to a sub process - and getting a result back. + and getting a result back. XXX lots of things missing here XXX Changes between 0.9.1 and 0.9.2 =============================== -* refined installation and metadata, created new setup.py, - now based on setuptools/ez_setup (thanks to Ralf Schmitt +* refined installation and metadata, created new setup.py, + now based on setuptools/ez_setup (thanks to Ralf Schmitt for his support). -* improved the way of making py.* scripts available in - windows environments, they are now added to the - Scripts directory as ".cmd" files. +* improved the way of making py.* scripts available in + windows environments, they are now added to the + Scripts directory as ".cmd" files. -* py.path.svnwc.status() now is more complete and +* py.path.svnwc.status() now is more complete and uses xml output from the 'svn' command if available (Guido Wesdorp) * fix for py.path.svn* to work with svn 1.5 (Chris Lamb) -* fix path.relto(otherpath) method on windows to +* fix path.relto(otherpath) method on windows to use normcase for checking if a path is relative. -* py.test's traceback is better parseable from editors +* py.test's traceback is better parseable from editors (follows the filenames:LINENO: MSG convention) (thanks to Osmo Salomaa) -* fix to javascript-generation, "py.test --runbrowser" +* fix to javascript-generation, "py.test --runbrowser" should work more reliably now -* removed previously accidentally added - py.test.broken and py.test.notimplemented helpers. +* removed previously accidentally added + py.test.broken and py.test.notimplemented helpers. * there now is a py.__version__ attribute diff --git a/doc/bin.txt b/doc/bin.txt index 70a156811..ee04819f3 100644 --- a/doc/bin.txt +++ b/doc/bin.txt @@ -1,11 +1,11 @@ ====================== -pylib scripts +pylib scripts ====================== The pylib installs several scripts to support testing and (python) development. If working from a checkout you may also add ``bin`` to your ``PATH`` environment variable which makes the scripts available on -your shell prompt. +your shell prompt. ``py.test`` and ``py.test-$VERSION`` ============================================ @@ -14,16 +14,16 @@ The ``py.test`` executable is the main tool that the py lib offers; in fact most code in the py lib is geared towards supporting the testing process. See the `py.test documentation`_ for extensive documentation. The ``py.test-$VERSION`` is the same script with -an interpreter specific suffix appended to make +an interpreter specific suffix appended to make several versions of py.test for using specific interpreters accessible: -* CPython2.4: py.test-2.4 +* CPython2.4: py.test-2.4 * CPython2.5: py.test-2.5 -* ... +* ... * CPython3.1: py.test-3.1 * Jython-2.5.1: py.test-jython -* pypy-$SUFFIX: py.test-pypy-$SUFFIX +* pypy-$SUFFIX: py.test-pypy-$SUFFIX .. _`py.test documentation`: test/index.html @@ -33,7 +33,7 @@ accessible: Usage: ``py.which modulename`` Print the ``__file__`` of the module that is imported via ``import modulename``. -The version-suffix is the same as with ``py.test`` above. +The version-suffix is the same as with ``py.test`` above. ``py.cleanup`` ============== diff --git a/doc/code.txt b/doc/code.txt index 1fd1eaef7..d69610ab5 100644 --- a/doc/code.txt +++ b/doc/code.txt @@ -18,7 +18,7 @@ Contents of the library Every object in the ``py.code`` library wraps a code Python object related to code objects, source code, frames and tracebacks: the ``py.code.Code`` class wraps code objects, ``py.code.Source`` source snippets, -``py.code.Traceback` exception tracebacks, ``py.code.Frame`` frame +``py.code.Traceback` exception tracebacks, ``py.code.Frame`` frame objects (as found in e.g. tracebacks) and ``py.code.ExceptionInfo`` the tuple provided by sys.exc_info() (containing exception and traceback information when an exception occurs). Also in the library is a helper function diff --git a/doc/confrest.py b/doc/confrest.py index 8bc6fa5f3..55401da6d 100644 --- a/doc/confrest.py +++ b/doc/confrest.py @@ -2,7 +2,7 @@ import py from py._plugin.pytest_restdoc import convert_rest_html, strip_html_header -html = py.xml.html +html = py.xml.html class css: #pagetitle = "pagetitle" @@ -11,7 +11,7 @@ class css: navspace = "navspace" versioninfo = "versioninfo" -class Page(object): +class Page(object): doctype = ('\n') googlefragment = """ @@ -27,18 +27,18 @@ pageTracker._trackPageview(); """ def __init__(self, project, title, targetpath, stylesheeturl=None, - type="text/html", encoding="ISO-8859-1"): - self.project = project - self.title = project.prefix_title + title + type="text/html", encoding="ISO-8859-1"): + self.project = project + self.title = project.prefix_title + title self.targetpath = targetpath - self.stylesheeturl = stylesheeturl - self.type = type - self.encoding = encoding + self.stylesheeturl = stylesheeturl + self.type = type + self.encoding = encoding self.body = html.body() - self.head = html.head() - self._root = html.html(self.head, self.body) - self.fill() + self.head = html.head() + self._root = html.html(self.head, self.body) + self.fill() def a_href(self, name, url, **kwargs): return html.a(name, class_="menu", href=url, **kwargs) @@ -54,7 +54,7 @@ pageTracker._trackPageview(); return html.a(name, class_="menu", href=relpath(self.targetpath.strpath, apipath.join(relhtmlpath).strpath)) - + def fill_menubar(self): items = [ self.a_docref("INSTALL", "install.html"), @@ -73,7 +73,7 @@ pageTracker._trackPageview(); self.a_href("hudson-tests", "http://hudson.testrun.org") ), html.div( - html.h3("supporting APIs:"), + html.h3("supporting APIs:"), self.a_docref("Index", "index.html"), self.a_docref("py.path", "path.html"), self.a_docref("py.code", "code.html"), @@ -86,12 +86,12 @@ pageTracker._trackPageview(); self.menubar = html.div(id=css.menubar, *[ html.div(item) for item in items]) version = py.version - announcelink = self.a_docref("%s ANN" % version, + announcelink = self.a_docref("%s ANN" % version, "announce/release-%s.html" %(version,)) - self.menubar.insert(0, + self.menubar.insert(0, html.div(announcelink)) - #self.a_href("%s-%s" % (self.title, py.version), - # "http://pypi.python.org/pypi/py/%s" % version, + #self.a_href("%s-%s" % (self.title, py.version), + # "http://pypi.python.org/pypi/py/%s" % version, #id="versioninfo", def fill(self): @@ -108,31 +108,31 @@ pageTracker._trackPageview(); self.body.append(html.div( self.project.logo, self.menubar, - id=css.navspace, + id=css.navspace, )) - + #self.body.append(html.div(self.title, id=css.pagetitle)) self.contentspace = html.div(id=css.contentspace) self.body.append(self.contentspace) - def unicode(self, doctype=True): - page = self._root.unicode() + def unicode(self, doctype=True): + page = self._root.unicode() page = page.replace("", self.googlefragment + "") - if doctype: - return self.doctype + page - else: - return page + if doctype: + return self.doctype + page + else: + return page -class PyPage(Page): +class PyPage(Page): def get_menubar(self): menubar = super(PyPage, self).get_menubar() - # base layout + # base layout menubar.append( html.a("issue", href="https://codespeak.net/issue/py-dev/", class_="menu"), ) return menubar - + def getrealname(username): try: @@ -143,30 +143,30 @@ def getrealname(username): user = uconf.system.User(username) except KeyboardInterrupt: raise - try: + try: return user.realname or username except KeyError: return username - + class Project: mydir = py.path.local(__file__).dirpath() title = "py lib" prefix_title = "" # we have a logo already containing "py lib" - encoding = 'latin1' + encoding = 'latin1' logo = html.div( html.a( - html.img(alt="py lib", id='pyimg', height=114/2, width=154/2, - src="http://codespeak.net/img/pylib.png"), + html.img(alt="py lib", id='pyimg', height=114/2, width=154/2, + src="http://codespeak.net/img/pylib.png"), href="http://pylib.org")) - Page = PyPage + Page = PyPage def __init__(self, sourcepath=None): if sourcepath is None: sourcepath = self.mydir self.setpath(sourcepath) - def setpath(self, sourcepath, docpath=None, + def setpath(self, sourcepath, docpath=None, apigenpath=None, stylesheet=None): self.sourcepath = sourcepath if docpath is None: @@ -197,7 +197,7 @@ class Project: reloutputpath = txtpath.new(ext='.html').relto(self.sourcepath) return self.docpath.join(reloutputpath) - def process(self, txtpath): + def process(self, txtpath): encoding = self.encoding content = self.get_content(txtpath, encoding) outputpath = self.get_htmloutputpath(txtpath) @@ -214,16 +214,16 @@ class Project: stylesheet=stylesheet, encoding=encoding) content = strip_html_header(content, encoding=encoding) - title = txtpath.purebasename + title = txtpath.purebasename if txtpath.dirpath().basename == "test": title = "py.test " + title # title = "[%s] %s" % (txtpath.purebasename, py.version) - page = self.Page(self, title, + page = self.Page(self, title, outputpath, stylesheeturl=stylesheet) try: modified = py.process.cmdexec( - "hg tip --template 'modified {date|shortdate}'" + "hg tip --template 'modified {date|shortdate}'" ) except py.process.cmdexec.Error: modified = " " @@ -231,10 +231,10 @@ class Project: #page.body.append(html.div(modified, id="docinfoline")) page.contentspace.append(py.xml.raw(content)) - outputpath.ensure().write(page.unicode().encode(encoding)) + outputpath.ensure().write(page.unicode().encode(encoding)) # XXX this function comes from apigen/linker.py, put it -# somewhere in py lib +# somewhere in py lib import os def relpath(p1, p2, sep=os.path.sep, back='..', normalize=True): """ create a relative path from p1 to p2 @@ -268,7 +268,7 @@ def relpath(p1, p2, sep=os.path.sep, back='..', normalize=True): # AA BB # AA CC -> CC # - # AA BB + # AA BB # AA -> ../AA diffindex = 0 diff --git a/doc/contact.txt b/doc/contact.txt index 1e79902df..4bd2fa7dd 100644 --- a/doc/contact.txt +++ b/doc/contact.txt @@ -1,50 +1,50 @@ -Contact and Communication points +Contact and Communication points =================================== -- `py-dev developers list`_ announcements and discussions. +- `py-dev developers list`_ announcements and discussions. -- #pylib on irc.freenode.net IRC channel for random questions. +- #pylib on irc.freenode.net IRC channel for random questions. -- `tetamap`_: Holger Krekel's blog, often about testing and py.test related news. +- `tetamap`_: Holger Krekel's blog, often about testing and py.test related news. -- `Testing In Python`_: a mailing list for testing tools and discussion. +- `Testing In Python`_: a mailing list for testing tools and discussion. -- `commit mailing list`_ or `@pylibcommit`_ to follow development commits, +- `commit mailing list`_ or `@pylibcommit`_ to follow development commits, - `bitbucket issue tracker`_ use this bitbucket issue tracker to report - bugs or request features. + bugs or request features. -- `merlinux.eu`_ offers on-site teaching and consulting services. +- `merlinux.eu`_ offers on-site teaching and consulting services. -.. _`bitbucket issue tracker`: http://bitbucket.org/hpk42/py-trunk/issues/ +.. _`bitbucket issue tracker`: http://bitbucket.org/hpk42/py-trunk/issues/ .. _`merlinux.eu`: http://merlinux.eu -.. _`get an account`: +.. _`get an account`: .. _tetamap: http://tetamap.wordpress.com -.. _`@pylibcommit`: http://twitter.com/pylibcommit +.. _`@pylibcommit`: http://twitter.com/pylibcommit -.. - get an account on codespeak - --------------------------- +.. + get an account on codespeak + --------------------------- - codespeak_ is where the subversion repository is hosted. If you know - someone who is active on codespeak already or you are otherwise known in - the community (see also: FOAF_) you will get access. But even if - you are new to the python developer community please come to the IRC - or the mailing list and ask questions, get involved. + codespeak_ is where the subversion repository is hosted. If you know + someone who is active on codespeak already or you are otherwise known in + the community (see also: FOAF_) you will get access. But even if + you are new to the python developer community please come to the IRC + or the mailing list and ask questions, get involved. .. _`Testing in Python`: http://lists.idyll.org/listinfo/testing-in-python .. _FOAF: http://en.wikipedia.org/wiki/FOAF .. _us: http://codespeak.net/mailman/listinfo/py-dev .. _codespeak: http://codespeak.net/ -.. _`py-dev`: -.. _`development mailing list`: -.. _`py-dev developers list`: http://codespeak.net/mailman/listinfo/py-dev -.. _`py-svn`: -.. _`commit mailing list`: http://codespeak.net/mailman/listinfo/py-svn +.. _`py-dev`: +.. _`development mailing list`: +.. _`py-dev developers list`: http://codespeak.net/mailman/listinfo/py-dev +.. _`py-svn`: +.. _`commit mailing list`: http://codespeak.net/mailman/listinfo/py-svn diff --git a/doc/example/assertion/failure_demo.py b/doc/example/assertion/failure_demo.py index f3e793ef2..5fba99db7 100644 --- a/doc/example/assertion/failure_demo.py +++ b/doc/example/assertion/failure_demo.py @@ -7,9 +7,9 @@ def otherfunc(a,b): def somefunc(x,y): otherfunc(x,y) -def otherfunc_multi(a,b): - assert (a == - b) +def otherfunc_multi(a,b): + assert (a == + b) def test_generative(param1, param2): assert param1 * 2 < param2 diff --git a/doc/example/assertion/global_testmodule_config/test_hello.py b/doc/example/assertion/global_testmodule_config/test_hello.py index 882e36acd..828e6b9fd 100644 --- a/doc/example/assertion/global_testmodule_config/test_hello.py +++ b/doc/example/assertion/global_testmodule_config/test_hello.py @@ -1,5 +1,5 @@ hello = "world" -def test_func(): +def test_func(): pass diff --git a/doc/example/assertion/test_failures.py b/doc/example/assertion/test_failures.py index 77bb3797c..2f223d0d2 100644 --- a/doc/example/assertion/test_failures.py +++ b/doc/example/assertion/test_failures.py @@ -4,7 +4,7 @@ failure_demo = py.path.local(__file__).dirpath('failure_demo.py') pytest_plugins = "pytest_pytester" -def test_failure_demo_fails_properly(testdir): +def test_failure_demo_fails_properly(testdir): target = testdir.tmpdir.join(failure_demo.basename) failure_demo.copy(target) failure_demo.copy(testdir.tmpdir.join(failure_demo.basename)) diff --git a/doc/example/funcarg/costlysetup/conftest.py b/doc/example/funcarg/costlysetup/conftest.py index 07c2a5802..b206395ba 100644 --- a/doc/example/funcarg/costlysetup/conftest.py +++ b/doc/example/funcarg/costlysetup/conftest.py @@ -1,7 +1,7 @@ def pytest_funcarg__setup(request): return request.cached_setup( - setup=lambda: CostlySetup(), + setup=lambda: CostlySetup(), teardown=lambda costlysetup: costlysetup.finalize(), scope="session", ) @@ -13,4 +13,4 @@ class CostlySetup: self.timecostly = 1 def finalize(self): - del self.timecostly + del self.timecostly diff --git a/doc/example/funcarg/mysetup/__init__.py b/doc/example/funcarg/mysetup/__init__.py index 759f52c49..effcb85e6 100644 --- a/doc/example/funcarg/mysetup/__init__.py +++ b/doc/example/funcarg/mysetup/__init__.py @@ -1 +1 @@ -# XXX this file should not need to be here but is here for proper sys.path mangling +# XXX this file should not need to be here but is here for proper sys.path mangling diff --git a/doc/example/funcarg/mysetup/test_sample.py b/doc/example/funcarg/mysetup/test_sample.py index 167d16a47..56e9b52b3 100644 --- a/doc/example/funcarg/mysetup/test_sample.py +++ b/doc/example/funcarg/mysetup/test_sample.py @@ -1,5 +1,5 @@ -def test_answer(mysetup): +def test_answer(mysetup): app = mysetup.myapp() answer = app.question() assert answer == 42 diff --git a/doc/example/funcarg/mysetup2/__init__.py b/doc/example/funcarg/mysetup2/__init__.py index 759f52c49..effcb85e6 100644 --- a/doc/example/funcarg/mysetup2/__init__.py +++ b/doc/example/funcarg/mysetup2/__init__.py @@ -1 +1 @@ -# XXX this file should not need to be here but is here for proper sys.path mangling +# XXX this file should not need to be here but is here for proper sys.path mangling diff --git a/doc/example/funcarg/mysetup2/conftest.py b/doc/example/funcarg/mysetup2/conftest.py index ccce42450..f598a179f 100644 --- a/doc/example/funcarg/mysetup2/conftest.py +++ b/doc/example/funcarg/mysetup2/conftest.py @@ -7,11 +7,11 @@ def pytest_funcarg__mysetup(request): def pytest_addoption(parser): parser.addoption("--ssh", action="store", default=None, help="specify ssh host to run tests with") - + class MySetup: def __init__(self, request): - self.config = request.config + self.config = request.config def myapp(self): return MyApp() @@ -21,4 +21,4 @@ class MySetup: if host is None: py.test.skip("specify ssh host with --ssh") return execnet.SshGateway(host) - + diff --git a/doc/example/funcarg/mysetup2/myapp.py b/doc/example/funcarg/mysetup2/myapp.py index 60fcada9b..2ecd83d11 100644 --- a/doc/example/funcarg/mysetup2/myapp.py +++ b/doc/example/funcarg/mysetup2/myapp.py @@ -1,5 +1,5 @@ class MyApp: def question(self): - return 6 * 9 + return 6 * 9 diff --git a/doc/example/funcarg/mysetup2/test_sample.py b/doc/example/funcarg/mysetup2/test_sample.py index c11f3bb45..58fd7874d 100644 --- a/doc/example/funcarg/mysetup2/test_sample.py +++ b/doc/example/funcarg/mysetup2/test_sample.py @@ -1,5 +1,5 @@ -def test_answer(mysetup): +def test_answer(mysetup): app = mysetup.myapp() answer = app.question() assert answer == 42 diff --git a/doc/example/funcarg/mysetup2/test_ssh.py b/doc/example/funcarg/mysetup2/test_ssh.py index b70666969..7b888779f 100644 --- a/doc/example/funcarg/mysetup2/test_ssh.py +++ b/doc/example/funcarg/mysetup2/test_ssh.py @@ -2,4 +2,4 @@ class TestClass: def test_function(self, mysetup): conn = mysetup.getsshconnection() - # work with conn + # work with conn diff --git a/doc/example/funcarg/parametrize/test_parametrize.py b/doc/example/funcarg/parametrize/test_parametrize.py index f0d2b7832..1d4bf1faf 100644 --- a/doc/example/funcarg/parametrize/test_parametrize.py +++ b/doc/example/funcarg/parametrize/test_parametrize.py @@ -3,13 +3,13 @@ import py def pytest_generate_tests(metafunc): for funcargs in metafunc.cls.params[metafunc.function.__name__]: metafunc.addcall(funcargs=funcargs) - + class TestClass: params = { 'test_equals': [dict(a=1, b=2), dict(a=3, b=3), dict(a=5, b=4)], 'test_zerodivision': [dict(a=1, b=0), dict(a=3, b=2)], } - + def test_equals(self, a, b): assert a == b diff --git a/doc/example/funcarg/parametrize/test_parametrize2.py b/doc/example/funcarg/parametrize/test_parametrize2.py index 149691c4f..a4371452e 100644 --- a/doc/example/funcarg/parametrize/test_parametrize2.py +++ b/doc/example/funcarg/parametrize/test_parametrize2.py @@ -13,7 +13,7 @@ def pytest_generate_tests(metafunc): # actual test code - + class TestClass: @params([dict(a=1, b=2), dict(a=3, b=3), dict(a=5, b=4)], ) def test_equals(self, a, b): diff --git a/doc/example/funcarg/parametrize/test_parametrize3.py b/doc/example/funcarg/parametrize/test_parametrize3.py index 7636f8c09..570b22ac2 100644 --- a/doc/example/funcarg/parametrize/test_parametrize3.py +++ b/doc/example/funcarg/parametrize/test_parametrize3.py @@ -1,5 +1,5 @@ -# following hook can be put unchanged into a local or global plugin +# following hook can be put unchanged into a local or global plugin def pytest_generate_tests(metafunc): for scenario in metafunc.cls.scenarios: metafunc.addcall(id=scenario[0], funcargs=scenario[1]) @@ -12,4 +12,4 @@ class TestSampleWithScenarios: scenarios = [scenario1, scenario2] def test_demo(self, attribute): - assert isinstance(attribute, str) + assert isinstance(attribute, str) diff --git a/doc/example/funcarg/test_multi_python.py b/doc/example/funcarg/test_multi_python.py index f2d3d88c1..f386d163a 100644 --- a/doc/example/funcarg/test_multi_python.py +++ b/doc/example/funcarg/test_multi_python.py @@ -1,22 +1,22 @@ """ module containing a parametrized tests testing cross-python -serialization via the pickle module. +serialization via the pickle module. """ import py -pythonlist = ['python2.3', 'python2.4', 'python2.5', 'python2.6'] +pythonlist = ['python2.3', 'python2.4', 'python2.5', 'python2.6'] # 'jython' 'python3.1'] - + def pytest_generate_tests(metafunc): if 'python1' in metafunc.funcargnames: assert 'python2' in metafunc.funcargnames for obj in metafunc.function.multiarg.kwargs['obj']: for py1 in pythonlist: for py2 in pythonlist: - metafunc.addcall(id="%s-%s-%s" % (py1, py2, obj), + metafunc.addcall(id="%s-%s-%s" % (py1, py2, obj), param=(py1, py2, obj)) - + @py.test.mark.multiarg(obj=[42, {}, {1:3},]) def test_basic_objects(python1, python2, obj): python1.dumps(obj) @@ -49,7 +49,7 @@ class Python: f.close() """ % (str(self.picklefile), obj))) py.process.cmdexec("%s %s" %(self.pythonpath, dumpfile)) - + def load_and_is_true(self, expression): loadfile = self.picklefile.dirpath("load.py") loadfile.write(py.code.Source(""" diff --git a/doc/example/funcarg/urloption/conftest.py b/doc/example/funcarg/urloption/conftest.py index 5f7bc846e..c764dc6ac 100644 --- a/doc/example/funcarg/urloption/conftest.py +++ b/doc/example/funcarg/urloption/conftest.py @@ -1,15 +1,15 @@ -# conftest.py +# conftest.py import py def pytest_addoption(parser): - grp = parser.getgroup("testserver options") + grp = parser.getgroup("testserver options") grp.addoption("--url", action="store", default=None, - help="url for testserver") + help="url for testserver") -def pytest_funcarg__url(request): - url = request.config.getvalue("url") - if url is None: - py.test.skip("need --url") - return url +def pytest_funcarg__url(request): + url = request.config.getvalue("url") + if url is None: + py.test.skip("need --url") + return url diff --git a/doc/example/genhtml.py b/doc/example/genhtml.py index 38bdef7f7..b5c8f525b 100644 --- a/doc/example/genhtml.py +++ b/doc/example/genhtml.py @@ -1,10 +1,10 @@ -from py.xml import html +from py.xml import html paras = "First Para", "Second para" doc = html.html( html.head( - html.meta(name="Content-Type", value="text/html; charset=latin1")), + html.meta(name="Content-Type", value="text/html; charset=latin1")), html.body( [html.p(p) for p in paras])) diff --git a/doc/example/genhtmlcss.py b/doc/example/genhtmlcss.py index d5c8158ae..3e6d0af54 100644 --- a/doc/example/genhtmlcss.py +++ b/doc/example/genhtmlcss.py @@ -1,23 +1,23 @@ import py -html = py.xml.html +html = py.xml.html class my(html): - "a custom style" - class body(html.body): - style = html.Style(font_size = "120%") + "a custom style" + class body(html.body): + style = html.Style(font_size = "120%") - class h2(html.h2): + class h2(html.h2): style = html.Style(background = "grey") - class p(html.p): + class p(html.p): style = html.Style(font_weight="bold") doc = my.html( - my.head(), + my.head(), my.body( my.h2("hello world"), - my.p("bold as bold can") + my.p("bold as bold can") ) ) - -print doc.unicode(indent=2) + +print doc.unicode(indent=2) diff --git a/doc/example/genxml.py b/doc/example/genxml.py index fca24d4e0..5f754e889 100644 --- a/doc/example/genxml.py +++ b/doc/example/genxml.py @@ -1,16 +1,16 @@ -import py -class ns(py.xml.Namespace): - pass +import py +class ns(py.xml.Namespace): + pass doc = ns.books( ns.book( - ns.author("May Day"), - ns.title("python for java programmers"),), - ns.book( - ns.author("why", class_="somecssclass"), + ns.author("May Day"), + ns.title("python for java programmers"),), + ns.book( + ns.author("why", class_="somecssclass"), ns.title("Java for Python programmers"),), - publisher="N.N", + publisher="N.N", ) print doc.unicode(indent=2).encode('utf8') diff --git a/doc/execnet.txt b/doc/execnet.txt index b284657d0..1d585f589 100644 --- a/doc/execnet.txt +++ b/doc/execnet.txt @@ -1,12 +1,12 @@ ============================================================================== -py.execnet: *elastic* distributed programming +py.execnet: *elastic* distributed programming ============================================================================== Since pylib 1.1 "py.execnet" ceased to exist and is now available as a separately developed `execnet standalone package`_. -If you have previosly used "py.execnet.*" and the 1.0 API just -rename all occurences of the string "``py.execnet.``" with the +If you have previosly used "py.execnet.*" and the 1.0 API just +rename all occurences of the string "``py.execnet.``" with the string "``execnet.``" as execnet-1.0 is API compatible. -.. _`execnet standalone package`: http://codespeak.net/execnet +.. _`execnet standalone package`: http://codespeak.net/execnet diff --git a/doc/faq.txt b/doc/faq.txt index c56965ec1..52cb4b3fb 100644 --- a/doc/faq.txt +++ b/doc/faq.txt @@ -1,71 +1,71 @@ ================================== -Frequently Asked Questions +Frequently Asked Questions ================================== -.. contents:: +.. contents:: :local: :depth: 2 -On naming, nosetests, licensing and magic +On naming, nosetests, licensing and magic =========================================== -Why the ``py`` naming? Why not ``pytest``? +Why the ``py`` naming? Why not ``pytest``? ---------------------------------------------------- -This mostly has historic reasons - the aim is +This mostly has historic reasons - the aim is to get away from the somewhat questionable 'py' name at some point. These days (2010) the 'py' library almost completely comprises APIs that are used by the ``py.test`` tool. There also are some other uses, e.g. of the ``py.path.local()`` and other path implementations. So it requires some -work to factor them out and do the shift. +work to factor them out and do the shift. -Why the ``py.test`` naming? +Why the ``py.test`` naming? ------------------------------------ because of TAB-completion under Bash/Shells. If you hit ``py.`` you'll get a list of available development tools that all share the ``py.`` prefix. Another motivation -was to unify the package ("py.test") and tool filename. +was to unify the package ("py.test") and tool filename. -What's py.test's relation to ``nosetests``? +What's py.test's relation to ``nosetests``? --------------------------------------------- py.test and nose_ share basic philosophy when it comes -to running Python tests. In fact, -with py.test-1.1.0 it is ever easier to run many test suites -that currently work with ``nosetests``. nose_ was created -as a clone of ``py.test`` when py.test was in the ``0.8`` release -cycle so some of the newer features_ introduced with py.test-1.0 -and py.test-1.1 have no counterpart in nose_. +to running Python tests. In fact, +with py.test-1.1.0 it is ever easier to run many test suites +that currently work with ``nosetests``. nose_ was created +as a clone of ``py.test`` when py.test was in the ``0.8`` release +cycle so some of the newer features_ introduced with py.test-1.0 +and py.test-1.1 have no counterpart in nose_. .. _nose: http://somethingaboutorange.com/mrl/projects/nose/0.11.1/ .. _features: test/features.html .. _apipkg: http://pypi.python.org/pypi/apipkg -What's this "magic" with py.test? +What's this "magic" with py.test? ---------------------------------------- issues where people have used the term "magic" in the past: * `py/__init__.py`_ uses the apipkg_ mechanism for lazy-importing - and full control on what API you get when importing "import py". - -* when an ``assert`` statement fails, py.test re-interprets the expression + and full control on what API you get when importing "import py". + +* when an ``assert`` statement fails, py.test re-interprets the expression to show intermediate values if a test fails. If your expression has side effects the intermediate values may not be the same, obfuscating - the initial error (this is also explained at the command line if it happens). - ``py.test --no-assert`` turns off assert re-intepretation. - Sidenote: it is good practise to avoid asserts with side effects. + the initial error (this is also explained at the command line if it happens). + ``py.test --no-assert`` turns off assert re-intepretation. + Sidenote: it is good practise to avoid asserts with side effects. .. _`py namespaces`: index.html .. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py -Where does my ``py.test`` come/import from? +Where does my ``py.test`` come/import from? ---------------------------------------------- You can issue:: @@ -80,17 +80,17 @@ function arguments, parametrized tests and setup .. _funcargs: test/funcargs.html -Is using funcarg- versus xUnit-based setup a style question? +Is using funcarg- versus xUnit-based setup a style question? --------------------------------------------------------------- It depends. For simple applications or for people experienced -with nose_ or unittest-style test setup using `xUnit style setup`_ +with nose_ or unittest-style test setup using `xUnit style setup`_ make some sense. For larger test suites, parametrized testing or setup of complex test resources using funcargs_ is recommended. -Moreover, funcargs are ideal for writing advanced test support -code (like e.g. the monkeypatch_, the tmpdir_ or capture_ funcargs) -because the support code can register setup/teardown functions -in a managed class/module/function scope. +Moreover, funcargs are ideal for writing advanced test support +code (like e.g. the monkeypatch_, the tmpdir_ or capture_ funcargs) +because the support code can register setup/teardown functions +in a managed class/module/function scope. .. _monkeypatch: test/plugin/monkeypatch.html .. _tmpdir: test/plugin/tmpdir.html @@ -100,65 +100,65 @@ in a managed class/module/function scope. .. _`why pytest_pyfuncarg__ methods?`: -Why the ``pytest_funcarg__*`` name for funcarg factories? +Why the ``pytest_funcarg__*`` name for funcarg factories? --------------------------------------------------------------- When experimenting with funcargs an explicit registration mechanism was considered. But lacking a good use case for this indirection and flexibility we decided to go for `Convention over Configuration`_ and allow to directly specify the factory. Besides removing the need -for an indirection it allows to "grep" for ``pytest_funcarg__MYARG`` -and will safely find all factory functions for the ``MYARG`` function -argument. It helps to alleviate the de-coupling of function -argument usage and creation. +for an indirection it allows to "grep" for ``pytest_funcarg__MYARG`` +and will safely find all factory functions for the ``MYARG`` function +argument. It helps to alleviate the de-coupling of function +argument usage and creation. .. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration -Can I yield multiple values from a factory function? +Can I yield multiple values from a factory function? ----------------------------------------------------- There are two conceptual reasons why yielding from a factory function -is not possible: +is not possible: -* Calling factories for obtaining test function arguments - is part of setting up and running a test. At that +* Calling factories for obtaining test function arguments + is part of setting up and running a test. At that point it is not possible to add new test calls to - the test collection anymore. + the test collection anymore. * If multiple factories yielded values there would - be no natural place to determine the combination + be no natural place to determine the combination policy - in real-world examples some combinations - often should not run. + often should not run. Use the `pytest_generate_tests`_ hook to solve both issues and implement the `parametrization scheme of your choice`_. .. _`pytest_generate_tests`: test/funcargs.html#parametrizing-tests -.. _`parametrization scheme of your choice`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ +.. _`parametrization scheme of your choice`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ py.test interaction with other packages =============================================== -Issues with py.test, multiprocess and setuptools? +Issues with py.test, multiprocess and setuptools? ------------------------------------------------------------ -On windows the multiprocess package will instantiate sub processes -by pickling and thus implicitely re-import a lot of local modules. -Unfortuantely, setuptools-0.6.11 does not ``if __name__=='__main__'`` +On windows the multiprocess package will instantiate sub processes +by pickling and thus implicitely re-import a lot of local modules. +Unfortuantely, setuptools-0.6.11 does not ``if __name__=='__main__'`` protect its generated command line script. This leads to infinite recursion when running a test that instantiates Processes. -There are these workarounds: +There are these workarounds: -* `install Distribute`_ as a drop-in replacement for setuptools - and install py.test +* `install Distribute`_ as a drop-in replacement for setuptools + and install py.test * `directly use a checkout`_ which avoids all setuptools/Distribute - installation + installation If those options are not available to you, you may also manually fix the script that is created by setuptools by inserting an -``if __name__ == '__main__'``. Or you can create a "pytest.py" +``if __name__ == '__main__'``. Or you can create a "pytest.py" script with this content and invoke that with the python version:: import py diff --git a/doc/index.txt b/doc/index.txt index 6833d00e1..55562d4f6 100644 --- a/doc/index.txt +++ b/doc/index.txt @@ -1,26 +1,26 @@ -py lib: testing and filesystem abstraction +py lib: testing and filesystem abstraction ==================================================== The ``py`` lib has several namespaces which help with automated testing, -and with accessing filesystems. Here is some documentation on the +and with accessing filesystems. Here is some documentation on the core namespaces: -`py.test`_ write and deploy unit- and functional tests to multiple machines. +`py.test`_ write and deploy unit- and functional tests to multiple machines. -`py.code`_: generate code and use advanced introspection/traceback support. +`py.code`_: generate code and use advanced introspection/traceback support. `py.path`_: use path objects to transparently access local and svn filesystems. -Other (minor) support functionality +Other (minor) support functionality =================================== -`py lib scripts`_ to make python development easier. +`py lib scripts`_ to make python development easier. -`py.xml`_ for generating in-memory xml/html object trees +`py.xml`_ for generating in-memory xml/html object trees -`py.io`_: Helper Classes for Capturing of Input/Output +`py.io`_: Helper Classes for Capturing of Input/Output -`py.log`_: an alpha document about the ad-hoc logging facilities +`py.log`_: an alpha document about the ad-hoc logging facilities `miscellaneous features`_ describes some small but nice py lib features. @@ -29,13 +29,13 @@ Other (minor) support functionality For the latest Release, see `PyPI project page`_ -.. _`py-dev at codespeak net`: http://codespeak.net/mailman/listinfo/py-dev +.. _`py-dev at codespeak net`: http://codespeak.net/mailman/listinfo/py-dev .. _`py.log`: log.html .. _`py.io`: io.html .. _`py.path`: path.html .. _`py.code`: code.html -.. _`py.test`: test/index.html +.. _`py.test`: test/index.html .. _`py lib scripts`: bin.html -.. _`py.xml`: xml.html -.. _`miscellaneous features`: misc.html +.. _`py.xml`: xml.html +.. _`miscellaneous features`: misc.html diff --git a/doc/install.txt b/doc/install.txt index d1c418a5a..64d9b0c6f 100644 --- a/doc/install.txt +++ b/doc/install.txt @@ -6,9 +6,9 @@ py.test/pylib installation info in a nutshell **Pythons**: 2.4, 2.5, 2.6, 2.7, 3.0, 3.1.x, Jython-2.5.1, PyPy-1.2 -**Operating systems**: Linux, Windows, OSX, Unix +**Operating systems**: Linux, Windows, OSX, Unix -**Requirements**: setuptools_ or Distribute_ +**Requirements**: setuptools_ or Distribute_ **Installers**: easy_install_ and pip_ or `standalone`_ (new for 1.2) @@ -19,9 +19,9 @@ py.test/pylib installation info in a nutshell * debian: ``python-codespeak-lib`` * gentoo: ``pylib`` -**Installed scripts**: see `bin`_ for which and how scripts are installed. +**Installed scripts**: see `bin`_ for which and how scripts are installed. -**hg repository**: https://bitbucket.org/hpk42/py-trunk +**hg repository**: https://bitbucket.org/hpk42/py-trunk .. _`bin`: bin.html @@ -29,12 +29,12 @@ py.test/pylib installation info in a nutshell Best practise: install tool and dependencies virtually =========================================================== -It is recommended to work with virtual environments +It is recommended to work with virtual environments (e.g. virtualenv_ or buildout_ based) and use easy_install_ -(or pip_) for installing py.test/pylib and any dependencies -you need to run your tests. Local virtual Python environments -(as opposed to system-wide "global" environments) make for a more -reproducible and reliable test environment. +(or pip_) for installing py.test/pylib and any dependencies +you need to run your tests. Local virtual Python environments +(as opposed to system-wide "global" environments) make for a more +reproducible and reliable test environment. .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv @@ -46,22 +46,22 @@ using easy_install (from setuptools or Distribute) =================================================== Both `Distribute`_ and setuptools_ provide the ``easy_install`` -installation tool. While setuptools should work ok with -Python2 interpreters, `Distribute`_ also works with Python3 +installation tool. While setuptools should work ok with +Python2 interpreters, `Distribute`_ also works with Python3 and it avoids some issues on Windows. In both cases you can open a command line window and then type:: - easy_install -U py + easy_install -U py to install the latest release of the py lib and py.test. The ``-U`` switch -will trigger an upgrade if you already have an older version installed. +will trigger an upgrade if you already have an older version installed. If you now type:: py.test --version you should see the version number and the import location of the tool. -Maybe you want to head on with the `quickstart`_ now? +Maybe you want to head on with the `quickstart`_ now? .. _quickstart: test/quickstart.html @@ -70,19 +70,19 @@ Maybe you want to head on with the `quickstart`_ now? Generating a py.test standalone Script ============================================ -If you are a maintainer or application developer and want users +If you are a maintainer or application developer and want users to run tests you can use a facility to generate a standalone "py.test" script that you can tell users to run:: - py.test --genscript=mytest + py.test --genscript=mytest will generate a ``mytest`` script that is, in fact, a ``py.test`` under disguise. You can tell people to download and then e.g. run it like this:: - python mytest --pastebin=all + python mytest --pastebin=all -and ask them to send you the resulting URL. The resulting script has -all core features and runs unchanged under Python2 and Python3 interpreters. +and ask them to send you the resulting URL. The resulting script has +all core features and runs unchanged under Python2 and Python3 interpreters. Troubleshooting / known issues =============================== @@ -90,30 +90,30 @@ Troubleshooting / known issues .. _`Jython does not create command line launchers`: http://bugs.jython.org/issue1491 **Jython2.5.1 on XP**: `Jython does not create command line launchers`_ -so ``py.test`` will not work correctly. You may install py.test on -CPython and type ``py.test --genscript=mytest`` and then use -``jython mytest`` to run py.test for your tests to run in Jython. +so ``py.test`` will not work correctly. You may install py.test on +CPython and type ``py.test --genscript=mytest`` and then use +``jython mytest`` to run py.test for your tests to run in Jython. **On Linux**: If ``easy_install`` fails because it needs to run -as the superuser you are trying to install things globally -and need to put ``sudo`` in front of the command. +as the superuser you are trying to install things globally +and need to put ``sudo`` in front of the command. **On Windows**: If "easy_install" or "py.test" are not found please see here: `How do i run a Python program under Windows?`_ -.. _`How do i run a Python program under Windows?`: http://www.python.org/doc/faq/windows/#how-do-i-run-a-python-program-under-windows +.. _`How do i run a Python program under Windows?`: http://www.python.org/doc/faq/windows/#how-do-i-run-a-python-program-under-windows .. _mercurial: http://mercurial.selenic.com/wiki/ -.. _`Distribute`: +.. _`Distribute`: .. _`Distribute for installation`: http://pypi.python.org/pypi/distribute#installation-instructions .. _`distribute installation`: http://pypi.python.org/pypi/distribute .. _checkout: .. _tarball: -Working from version control or a tarball +Working from version control or a tarball ================================================= -To follow development or start experiments, checkout the +To follow development or start experiments, checkout the complete code and documentation source with mercurial_:: hg clone https://bitbucket.org/hpk42/py-trunk/ @@ -126,45 +126,45 @@ download and unpack a TAR file:: http://pypi.python.org/pypi/py/ -activating a checkout with setuptools +activating a checkout with setuptools -------------------------------------------- With a working `Distribute`_ or setuptools_ installation you can type:: - python setup.py develop + python setup.py develop -in order to work inline with the tools and the lib of your checkout. +in order to work inline with the tools and the lib of your checkout. .. _`no-setuptools`: -.. _`directly use a checkout`: +.. _`directly use a checkout`: -directly use a checkout or tarball / avoid setuptools +directly use a checkout or tarball / avoid setuptools ------------------------------------------------------------- Get a checkout_ or tarball_ and add paths to your environment variables: * ``PYTHONPATH`` needs to contain the root directory (where ``py`` resides) -* ``PATH`` needs to contain ``ROOT/bin`` or ``ROOT\bin\win32`` respectively. +* ``PATH`` needs to contain ``ROOT/bin`` or ``ROOT\bin\win32`` respectively. -There also are helper scripts that set the variables accordingly. On windows +There also are helper scripts that set the variables accordingly. On windows execute:: # inside autoexec.bat or shell startup c:\\path\to\checkout\bin\env.cmd -on linux/OSX add this to your shell initialization:: +on linux/OSX add this to your shell initialization:: - # inside e.g. .bashrc - eval `python ~/path/to/checkout/bin/env.py` + # inside e.g. .bashrc + eval `python ~/path/to/checkout/bin/env.py` -both of which which will get you good settings. If you install +both of which which will get you good settings. If you install the pylib this way you can easily ``hg pull && hg up`` or download a new tarball_ to follow the development tree. -Note that the scripts manually added like this will look for -py libs in the chain of parent directories of the current working dir. +Note that the scripts manually added like this will look for +py libs in the chain of parent directories of the current working dir. For example, if you have a layout like this:: mypkg/ @@ -179,7 +179,7 @@ the pylib comes from you can always do:: py.test --version -to see where py.test is imported from. +to see where py.test is imported from. .. _`command line scripts`: bin.html .. _contact: contact.html diff --git a/doc/io.txt b/doc/io.txt index 6fd686b2d..7ffd4c8d1 100644 --- a/doc/io.txt +++ b/doc/io.txt @@ -4,7 +4,7 @@ py.io The 'py' lib provides helper classes for capturing IO during -execution of a program. +execution of a program. IO Capturing examples =============================================== @@ -21,7 +21,7 @@ Basic Example:: >>> out.strip() == "hello" True -For calling functions you may use a shortcut:: +For calling functions you may use a shortcut:: >>> import py >>> def f(): print "hello" diff --git a/doc/log.txt b/doc/log.txt index 2c669cde9..a3d71a277 100644 --- a/doc/log.txt +++ b/doc/log.txt @@ -13,10 +13,10 @@ Foreword This document is an attempt to briefly state the actual specification of the :code:`py.log` module. It was written by Francois Pinard and also contains -some ideas for enhancing the py.log facilities. +some ideas for enhancing the py.log facilities. NOTE that :code:`py.log` is subject to refactorings, it may change with -the next release. +the next release. This document is meant to trigger or facilitate discussions. It shamelessly steals from the `Agile Testing`__ comments, and from other sources as well, @@ -204,5 +204,5 @@ log entry. .. ------------- .. XXX: fill in details .. + Should speak about pickle-ability of :code:`py.log`. -.. +.. .. + What is :code:`log.get` (in :file:`logger.py`)? diff --git a/doc/misc.txt b/doc/misc.txt index 22a35964b..8c3c0b3f7 100644 --- a/doc/misc.txt +++ b/doc/misc.txt @@ -1,21 +1,21 @@ ==================================== -Miscellaneous features of the py lib +Miscellaneous features of the py lib ==================================== -Mapping the standard python library into py +Mapping the standard python library into py =========================================== -The ``py.std`` object allows lazy access to +The ``py.std`` object allows lazy access to standard library modules. For example, to get to the print-exception -functionality of the standard library you can write:: +functionality of the standard library you can write:: py.std.traceback.print_exc() -without having to do anything else than the usual ``import py`` +without having to do anything else than the usual ``import py`` at the beginning. You can access any other top-level standard -library module this way. This means that you will only trigger +library module this way. This means that you will only trigger imports of modules that are actually needed. Note that no attempt -is made to import submodules. +is made to import submodules. Support for interaction with system utilities/binaries ====================================================== @@ -23,68 +23,68 @@ Support for interaction with system utilities/binaries Currently, the py lib offers two ways to interact with system executables. ``py.process.cmdexec()`` invokes the shell in order to execute a string. The other -one, ``py.path.local``'s 'sysexec()' method lets you -directly execute a binary. +one, ``py.path.local``'s 'sysexec()' method lets you +directly execute a binary. Both approaches will raise an exception in case of a return- -code other than 0 and otherwise return the stdout-output +code other than 0 and otherwise return the stdout-output of the child process. -The shell based approach +The shell based approach ------------------------ -You can execute a command via your system shell -by doing something like:: +You can execute a command via your system shell +by doing something like:: out = py.process.cmdexec('ls -v') -However, the ``cmdexec`` approach has a few shortcomings: +However, the ``cmdexec`` approach has a few shortcomings: - it relies on the underlying system shell - it neccessitates shell-escaping for expressing arguments -- it does not easily allow to "fix" the binary you want to run. -- it only allows to execute executables from the local - filesystem +- it does not easily allow to "fix" the binary you want to run. +- it only allows to execute executables from the local + filesystem -.. _sysexec: +.. _sysexec: local paths have ``sysexec`` ----------------------------- +---------------------------- -In order to synchronously execute an executable file you +In order to synchronously execute an executable file you can use ``sysexec``:: - binsvn.sysexec('ls', 'http://codespeak.net/svn') + binsvn.sysexec('ls', 'http://codespeak.net/svn') where ``binsvn`` is a path that points to the ``svn`` commandline binary. Note that this function does not offer any shell-escaping -so you have to pass in already separated arguments. +so you have to pass in already separated arguments. finding an executable local path -------------------------------- -Finding an executable is quite different on multiple platforms. +Finding an executable is quite different on multiple platforms. Currently, the ``PATH`` environment variable based search on -unix platforms is supported:: +unix platforms is supported:: py.path.local.sysfind('svn') -which returns the first path whose ``basename`` matches ``svn``. +which returns the first path whose ``basename`` matches ``svn``. In principle, `sysfind` deploys platform specific algorithms to perform the search. On Windows, for example, it may look -at the registry (XXX). +at the registry (XXX). -To make the story complete, we allow to pass in a second ``checker`` -argument that is called for each found executable. For example, if +To make the story complete, we allow to pass in a second ``checker`` +argument that is called for each found executable. For example, if you have multiple binaries available you may want to select the -right version:: +right version:: def mysvn(p): """ check that the given svn binary has version 1.1. """ line = p.execute('--version'').readlines()[0] - if line.find('version 1.1'): - return p - binsvn = py.path.local.sysfind('svn', checker=mysvn) + if line.find('version 1.1'): + return p + binsvn = py.path.local.sysfind('svn', checker=mysvn) Cross-Python Version compatibility helpers diff --git a/doc/path.txt b/doc/path.txt index 99dd9f65e..cd5306313 100644 --- a/doc/path.txt +++ b/doc/path.txt @@ -11,7 +11,7 @@ provides a number of implementations of this API. Path implementations provided by ``py.path`` =============================================== -.. _`local`: +.. _`local`: ``py.path.local`` -------------------- @@ -82,16 +82,16 @@ Common vs. specific API ======================= All Path objects support a common set of operations, suitable -for many use cases and allowing to transparently switch the -path object within an application (e.g. from "local" to "svnwc"). -The common set includes functions such as `path.read()` to read all data -from a file, `path.write()` to write data, `path.listdir()` to get a list +for many use cases and allowing to transparently switch the +path object within an application (e.g. from "local" to "svnwc"). +The common set includes functions such as `path.read()` to read all data +from a file, `path.write()` to write data, `path.listdir()` to get a list of directory entries, `path.check()` to check if a node exists and is of a particular type, `path.join()` to get to a (grand)child, `path.visit()` to recursively walk through a node's -children, etc. Only things that are not common on 'normal' filesystems (yet), +children, etc. Only things that are not common on 'normal' filesystems (yet), such as handling metadata (e.g. the Subversion "properties") require -using specific APIs. +using specific APIs. Examples --------------------------------- @@ -100,7 +100,7 @@ A quick 'cookbook' of small examples that will be useful 'in real life', which also presents parts of the 'common' API, and shows some non-common methods: -Searching `.txt` files +Searching `.txt` files .......................... Search for a particular string inside all files with a .txt extension in a @@ -122,7 +122,7 @@ specific directory. >>> results ['textfile1.txt', 'textfile2.txt', 'textfile2.txt'] -Working with Paths +Working with Paths ....................... This example shows the ``py.path`` features to deal with @@ -141,12 +141,12 @@ don't have to exist, either): 'baz/qux' >>> p2.bestrelpath(p1).replace(sep, '/') '../..' - >>> p2.join(p2.bestrelpath(p1)) == p1 + >>> p2.join(p2.bestrelpath(p1)) == p1 True >>> p3 = p1 / 'baz/qux' # the / operator allows joining, too >>> p2 == p3 True - >>> p4 = p1 + ".py" + >>> p4 = p1 + ".py" >>> p4.basename == "bar.py" True >>> p4.ext == ".py" @@ -185,7 +185,7 @@ allows you to check whether a file exists, what type it is, etc.: >>> file1.check(basename='file1') # we can use all the path's properties here True -Setting svn-properties +Setting svn-properties ....................... As an example of 'uncommon' methods, we'll show how to read and write @@ -230,44 +230,44 @@ Known problems / limitations =================================== * The SVN path objects require the "svn" command line, - there is currently no support for python bindings. + there is currently no support for python bindings. Parsing the svn output can lead to problems, particularly - regarding if you have a non-english "locales" setting. + regarding if you have a non-english "locales" setting. -* While the path objects basically work on windows, +* While the path objects basically work on windows, there is no attention yet on making unicode paths - work or deal with the famous "8.3" filename issues. + work or deal with the famous "8.3" filename issues. Future plans ============ The Subversion path implementations are based -on the `svn` command line, not on the bindings. -It makes sense now to directly use the bindings. +on the `svn` command line, not on the bindings. +It makes sense now to directly use the bindings. -Moreover, it would be good, also considering +Moreover, it would be good, also considering `execnet`_ distribution of programs, to be able to manipulate Windows Paths on Linux and vice versa. So we'd like to consider -refactoring the path implementations +refactoring the path implementations to provide this choice (and getting rid -of platform-dependencies as much as possible). +of platform-dependencies as much as possible). -There is some experimental small approach +There is some experimental small approach (``py/path/gateway/``) aiming at having -a convenient Remote Path implementation. +a convenient Remote Path implementation. There are various hacks out there to have Memory-Filesystems and even path objects -being directly mountable under Linux (via `fuse`). -However, the Path object implementations -do not internally have a clean abstraction +being directly mountable under Linux (via `fuse`). +However, the Path object implementations +do not internally have a clean abstraction of going to the filesystem - so with some -refactoring it should become easier to +refactoring it should become easier to have very custom Path objects, still offering -the quite full interface without requiring -to know about all details of the full path -implementation. +the quite full interface without requiring +to know about all details of the full path +implementation. .. _`execnet`: execnet.html diff --git a/doc/test/attic.txt b/doc/test/attic.txt index 25e3c5254..a1096c149 100644 --- a/doc/test/attic.txt +++ b/doc/test/attic.txt @@ -1,10 +1,10 @@ =============================================== -ATTIC documentation +ATTIC documentation =============================================== XXX REVIEW and remove the below XXX -Customizing the testing process +Customizing the testing process =============================== writing conftest.py files @@ -12,69 +12,69 @@ writing conftest.py files You may put conftest.py files containing project-specific configuration in your project's root directory, it's usually -best to put it just into the same directory level as your +best to put it just into the same directory level as your topmost ``__init__.py``. In fact, ``py.test`` performs -an "upwards" search starting from the directory that you specify -to be tested and will lookup configuration values right-to-left. -You may have options that reside e.g. in your home directory +an "upwards" search starting from the directory that you specify +to be tested and will lookup configuration values right-to-left. +You may have options that reside e.g. in your home directory but note that project specific settings will be considered first. There is a flag that helps you debugging your conftest.py configurations:: - + py.test --traceconfig -customizing the collecting and running process +customizing the collecting and running process ----------------------------------------------- -To introduce different test items you can create -one or more ``conftest.py`` files in your project. -When the collection process traverses directories -and modules the default collectors will produce -custom Collectors and Items if they are found -in a local ``conftest.py`` file. +To introduce different test items you can create +one or more ``conftest.py`` files in your project. +When the collection process traverses directories +and modules the default collectors will produce +custom Collectors and Items if they are found +in a local ``conftest.py`` file. Customizing the collection process in a module ----------------------------------------------- +---------------------------------------------- If you have a module where you want to take responsibility for collecting your own test Items and possibly even for executing -a test then you can provide `generative tests`_ that yield +a test then you can provide `generative tests`_ that yield callables and possibly arguments as a tuple. This is especially useful for calling application test machinery with different parameter sets but counting each of the calls as a separate -tests. +tests. .. _`generative tests`: features.html#generative-tests -The other extension possibility is about -specifying a custom test ``Item`` class which -is responsible for setting up and executing an underlying -test. Or you can extend the collection process for a whole -directory tree by putting Items in a ``conftest.py`` configuration file. -The collection process dynamically consults the *chain of conftest.py* -modules to determine collectors and items at ``Directory``, ``Module``, -``Class``, ``Function`` or ``Generator`` level respectively. +The other extension possibility is about +specifying a custom test ``Item`` class which +is responsible for setting up and executing an underlying +test. Or you can extend the collection process for a whole +directory tree by putting Items in a ``conftest.py`` configuration file. +The collection process dynamically consults the *chain of conftest.py* +modules to determine collectors and items at ``Directory``, ``Module``, +``Class``, ``Function`` or ``Generator`` level respectively. -Customizing execution of Items and Functions +Customizing execution of Items and Functions ---------------------------------------------------- -- ``py.test.collect.Function`` test items control execution +- ``py.test.collect.Function`` test items control execution of a test function through its ``function.runtest()`` method. - This method is responsible for performing setup and teardown - ("Test Fixtures") for a test Function. + This method is responsible for performing setup and teardown + ("Test Fixtures") for a test Function. - ``Function.execute(target, *args)`` methods are invoked by - the default ``Function.run()`` to actually execute a python - function with the given (usually empty set of) arguments. + the default ``Function.run()`` to actually execute a python + function with the given (usually empty set of) arguments. -.. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev +.. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev .. _`test generators`: funcargs.html#test-generators -.. _`generative tests`: +.. _`generative tests`: generative tests: yielding parametrized tests ==================================================== @@ -85,33 +85,33 @@ Deprecated since 1.0 in favour of `test generators`_. ``yield`` callables and their arguments. This is useful for running a test function multiple times against different parameters. Example:: - def test_generative(): - for x in (42,17,49): - yield check, x - - def check(arg): + def test_generative(): + for x in (42,17,49): + yield check, x + + def check(arg): assert arg % 7 == 0 # second generated tests fails! -Note that ``test_generative()`` will cause three tests +Note that ``test_generative()`` will cause three tests to get run, notably ``check(42)``, ``check(17)`` and ``check(49)`` -of which the middle one will obviously fail. +of which the middle one will obviously fail. To make it easier to distinguish the generated tests it is possible to specify an explicit name for them, like for example:: - def test_generative(): - for x in (42,17,49): - yield "case %d" % x, check, x + def test_generative(): + for x in (42,17,49): + yield "case %d" % x, check, x disabling a test class ----------------------- +---------------------- If you want to disable a complete test class you -can set the class-level attribute ``disabled``. -For example, in order to avoid running some tests on Win32:: +can set the class-level attribute ``disabled``. +For example, in order to avoid running some tests on Win32:: - class TestPosixOnly: + class TestPosixOnly: disabled = sys.platform == 'win32' - + def test_xxx(self): - ... + ... diff --git a/doc/test/customize.txt b/doc/test/customize.txt index ec2cdb5be..dff6b3e9d 100644 --- a/doc/test/customize.txt +++ b/doc/test/customize.txt @@ -1,26 +1,26 @@ ================================================ -Customizing and Extending py.test +Customizing and Extending py.test ================================================ -.. contents:: +.. contents:: :local: :depth: 2 -basic test configuration +basic test configuration =================================== -available command line options +available command line options --------------------------------- You can see command line options by running:: - py.test -h + py.test -h This will display all available command line options -in your specific environment. +in your specific environment. -.. _`project-specific test configuration`: -.. _`collect_ignore`: +.. _`project-specific test configuration`: +.. _`collect_ignore`: conftest.py: project specific hooks and configuration -------------------------------------------------------- @@ -36,33 +36,33 @@ allow to: or set particular variables to influence the testing process: -* ``pytest_plugins``: list of named plugins to load +* ``pytest_plugins``: list of named plugins to load -* ``collect_ignore``: list of paths to ignore during test collection, relative to the containing ``conftest.py`` file +* ``collect_ignore``: list of paths to ignore during test collection, relative to the containing ``conftest.py`` file * ``rsyncdirs``: list of to-be-rsynced directories for distributed - testing, relative to the containing ``conftest.py`` file. + testing, relative to the containing ``conftest.py`` file. You may put a conftest.py files in your project root directory or into -your package directory if you want to add project-specific test options. +your package directory if you want to add project-specific test options. ``py.test`` loads all ``conftest.py`` files upwards from the command line file arguments. It usually looks up configuration values right-to-left, i.e. the closer conftest files will be checked first. This means you can have a ``conftest.py`` in your very home directory to -have some global configuration values. +have some global configuration values. .. _`specify funcargs`: funcargs.html#application-setup-tutorial-example -.. _`set option defaults`: +.. _`set option defaults`: -setting persistent option defaults +setting persistent option defaults ------------------------------------ -py.test will lookup option values in this order: +py.test will lookup option values in this order: * command line -* conftest.py files +* conftest.py files * environment variables To find out about the particular switches and type:: @@ -70,19 +70,19 @@ To find out about the particular switches and type:: py.test --help-config This will print information about all options in your -environment, including your local plugins. +environment, including your local plugins. -.. _`basetemp`: +.. _`basetemp`: -Temporary directories +Temporary directories ------------------------------------------- You can create directories by calling one of two methods -on the config object: +on the config object: -- ``config.mktemp(basename)``: create and return a new tempdir +- ``config.mktemp(basename)``: create and return a new tempdir -- ``config.ensuretemp(basename)``: create or return a new tempdir +- ``config.ensuretemp(basename)``: create or return a new tempdir temporary directories are created as sub directories of a per-session testdir and will keep around the directories of the last three test @@ -90,12 +90,12 @@ runs. You can set the base temporary directory through the command line `--basetemp`` option. When distributing tests on the same machine, ``py.test`` takes care to configure a basetemp directory for the sub processes such that all temporary data lands below below a single -per-test run basetemp directory. +per-test run basetemp directory. .. _`function arguments`: funcargs.html -.. _`extensions`: +.. _`extensions`: -Plugin basics and project configuration +Plugin basics and project configuration ============================================= .. _`local plugin`: @@ -112,34 +112,34 @@ extensions close to your application. Named plugins are normal python modules or packages that can be distributed separately. Named plugins need to follow a naming pattern; they have an all lowercase ``pytest_`` prefixed name. While conftest plugins are discovered automatically, -named plugins must be explicitely specified. +named plugins must be explicitely specified. .. _`named plugins`: plugin/index.html .. _`tool startup`: -.. _`loaded at tool startup`: -.. _`test tool starts up`: +.. _`loaded at tool startup`: +.. _`test tool starts up`: Plugin discovery at tool startup -------------------------------------------- py.test loads plugin modules at tool startup in the following way: -* by loading all plugins registered through `setuptools entry points`_. +* by loading all plugins registered through `setuptools entry points`_. -* by reading the ``PYTEST_PLUGINS`` environment variable - and importing the comma-separated list of named plugins. +* by reading the ``PYTEST_PLUGINS`` environment variable + and importing the comma-separated list of named plugins. * by pre-scanning the command line for the ``-p name`` option - and loading the specified plugin before actual command line parsing. + and loading the specified plugin before actual command line parsing. * by loading all `conftest.py plugin`_ files as inferred by the command line - invocation (test files and all of its parent directories). + invocation (test files and all of its parent directories). Note that ``conftest.py`` files from sub directories are loaded - during test collection and not at tool startup. + during test collection and not at tool startup. -* by recursively loading all plugins specified by the - ``pytest_plugins`` variable in a ``conftest.py`` file +* by recursively loading all plugins specified by the + ``pytest_plugins`` variable in a ``conftest.py`` file Specifying plugins in a test module or plugin ----------------------------------------------- @@ -148,12 +148,12 @@ You can specify plugins in a test module or a plugin like this: .. sourcecode:: python - pytest_plugins = "name1", "name2", + pytest_plugins = "name1", "name2", When the test module or plugin is loaded the specified plugins will be loaded. If you specify plugins without the ``pytest_`` -prefix it will be automatically added. All plugin names -must be lowercase. +prefix it will be automatically added. All plugin names +must be lowercase. .. _`conftest.py plugin`: .. _`conftestplugin`: @@ -161,18 +161,18 @@ must be lowercase. Writing per-project plugins (conftest.py) ------------------------------------------------------ -The purpose of ``conftest.py`` files is to allow `project-specific -test configuration`_. They thus make for a good place to implement -project-specific test related features through hooks. For example you may +The purpose of ``conftest.py`` files is to allow `project-specific +test configuration`_. They thus make for a good place to implement +project-specific test related features through hooks. For example you may set the `collect_ignore`_ variable depending on a command line option by defining the following hook in a ``conftest.py`` file: -.. _`exclude-file-example`: +.. _`exclude-file-example`: .. sourcecode:: python - # ./conftest.py in your root or package dir - collect_ignore = ['hello', 'test_world.py'] + # ./conftest.py in your root or package dir + collect_ignore = ['hello', 'test_world.py'] def pytest_addoption(parser): parser.addoption("--runall", action="store_true", default=False) def pytest_configure(config): @@ -181,7 +181,7 @@ by defining the following hook in a ``conftest.py`` file: .. _`setuptools entry points`: -Writing setuptools-registered plugins +Writing setuptools-registered plugins ------------------------------------------------------ .. _`Distribute`: http://pypi.python.org/pypi/distribute @@ -190,13 +190,13 @@ Writing setuptools-registered plugins If you want to make your plugin publically available, you can use `setuptools`_ or `Distribute`_ which both allow to register an entry point. ``py.test`` will register -all objects with the ``pytest11`` entry point. +all objects with the ``pytest11`` entry point. To make your plugin available you may insert the following lines in your setuptools/distribute-based setup-invocation: .. sourcecode:: python - # sample ./setup.py file + # sample ./setup.py file from setuptools import setup setup( @@ -204,16 +204,16 @@ lines in your setuptools/distribute-based setup-invocation: packages = ['myproject'] # the following makes a plugin available to py.test - entry_points = { + entry_points = { 'pytest11': [ 'name_of_plugin = myproject.pluginmodule', ] }, ) -If a package is installed with this setup, py.test will load +If a package is installed with this setup, py.test will load ``myproject.pluginmodule`` under the ``name_of_plugin`` name -and use it as a plugin. +and use it as a plugin. Accessing another plugin by name -------------------------------------------- @@ -226,63 +226,63 @@ the plugin manager like this: plugin = config.pluginmanager.getplugin("name_of_plugin") -If you want to look at the names of existing plugins, use +If you want to look at the names of existing plugins, use the ``--traceconfig`` option. -.. _`well specified hooks`: -.. _`implement hooks`: +.. _`well specified hooks`: +.. _`implement hooks`: -Important py.test hooks +Important py.test hooks ==================================== py.test calls hooks functions to implement its `test collection`_, running and reporting process. When py.test loads a plugin it validates that all hook functions conform to the `hook definition specification`_. -The hook function name and its +The hook function name and its argument names need to match exactly but it is allowed for an implementation -to accept *less* parameters. You'll get useful errors on mistyped hook or -argument names. Read on for some introductory information on particular -hooks. It's sensible to look at existing plugins so see example usages -and start off with your own plugin. +to accept *less* parameters. You'll get useful errors on mistyped hook or +argument names. Read on for some introductory information on particular +hooks. It's sensible to look at existing plugins so see example usages +and start off with your own plugin. .. _`hook definition specification`: plugin/hookspec.html -.. _`configuration hooks`: +.. _`configuration hooks`: -command line parsing and configuration hooks +command line parsing and configuration hooks -------------------------------------------------------------------- When the `test tool starts up`_ it will invoke all hooks that add -command line options in the python standard optparse style. +command line options in the python standard optparse style. .. sourcecode:: python - def pytest_addoption(parser): - """ add command line options. """" + def pytest_addoption(parser): + """ add command line options. """" parser.addoption("--myopt", dest="myopt", action="store_true") -After all these hooks have been called, the command line is parser -and a ``config`` object is created and another hook is invoked, -for example: +After all these hooks have been called, the command line is parser +and a ``config`` object is created and another hook is invoked, +for example: .. sourcecode:: python - def pytest_configure(config): - config.getvalue("myopt") + def pytest_configure(config): + config.getvalue("myopt") When the test run finishes this corresponding finalizer hook is called: .. sourcecode:: python - def pytest_unconfigure(config): - ... + def pytest_unconfigure(config): + ... -adding global py.test helpers and functionality +adding global py.test helpers and functionality -------------------------------------------------------------------- -If you want to make global helper functions or objects available +If you want to make global helper functions or objects available to your test code you can implement: .. sourcecode:: python @@ -290,29 +290,29 @@ to your test code you can implement: def pytest_namespace(): """ return dictionary with items to be made available on py.test. namespace """ -All such returned items will be made available directly on -the ``py.test`` namespace. +All such returned items will be made available directly on +the ``py.test`` namespace. If you want to provide helpers that are specific to a test function run or need -to be setup per test function run, please refer to the `funcargs mechanism`_. +to be setup per test function run, please refer to the `funcargs mechanism`_. .. _`funcargs mechanism`: funcargs.html -generic "runtest" hooks +generic "runtest" hooks ------------------------------ Each test item is usually executed by calling the following three hooks: .. sourcecode:: python - pytest_runtest_setup(item) - pytest_runtest_call(item) - pytest_runtest_teardown(item) + pytest_runtest_setup(item) + pytest_runtest_call(item) + pytest_runtest_teardown(item) For each of the three invocations a `call object`_ encapsulates -information about the outcome of the call and is subsequently used -to make a report object: +information about the outcome of the call and is subsequently used +to make a report object: .. sourcecode:: python @@ -320,57 +320,57 @@ to make a report object: For example, the `pytest_pdb plugin`_ uses this hook to activate interactive debugging on failures when ``--pdb`` is specified on the -command line. +command line. Usually three reports will be generated for a single test item for each -of the three runtest hooks respectively. If ``pytest_runtest_setup`` -fails then ``pytest_runtest_teardown`` will be called but not -``pytest_runtest_call``. +of the three runtest hooks respectively. If ``pytest_runtest_setup`` +fails then ``pytest_runtest_teardown`` will be called but not +``pytest_runtest_call``. Each of the up to three reports is eventually fed to the logreport hook: .. sourcecode:: python - pytest_runtest_logreport(report) + pytest_runtest_logreport(report) A ``report`` object contains status and reporting information: .. sourcecode:: python - report.longrepr = string/lines/object to print - report.when = "setup", "call" or "teardown" - report.shortrepr = letter for progress-report + report.longrepr = string/lines/object to print + report.when = "setup", "call" or "teardown" + report.shortrepr = letter for progress-report report.passed = True or False report.failed = True or False report.skipped = True or False The `terminal plugin`_ uses this hook to print information -about a test run. - +about a test run. + The whole protocol described here is implemented via this hook: .. sourcecode:: python - - pytest_runtest_protocol(item) -> True -.. _`call object`: + pytest_runtest_protocol(item) -> True + +.. _`call object`: The call object contains information about a performed call: .. sourcecode:: python - call.excinfo = ExceptionInfo object or None - call.when = "setup", "call" or "teardown" - call.outerr = None or tuple of strings representing captured stdout/stderr + call.excinfo = ExceptionInfo object or None + call.when = "setup", "call" or "teardown" + call.outerr = None or tuple of strings representing captured stdout/stderr .. _`pytest_pdb plugin`: plugin/pdb.html .. _`terminal plugin`: plugin/terminal.html -generic collection hooks +generic collection hooks ------------------------------ -py.test calls the following two fundamental hooks for collecting files and directories: +py.test calls the following two fundamental hooks for collecting files and directories: .. sourcecode:: python @@ -380,17 +380,17 @@ py.test calls the following two fundamental hooks for collecting files and direc def pytest_collect_file(path, parent): """ return Collection node or None for the given path. """ -Both return a `collection node`_ for a given path. All returned +Both return a `collection node`_ for a given path. All returned nodes from all hook implementations will participate in the collection and running protocol. The ``parent`` object is the parent node and may be used to access command line -options via the ``parent.config`` object. +options via the ``parent.config`` object. -Python test function and module hooks +Python test function and module hooks ---------------------------------------------------- -For influencing the collection of objects in Python modules +For influencing the collection of objects in Python modules you can use the following hook: .. sourcecode:: python @@ -399,9 +399,9 @@ you can use the following hook: """ return custom item/collector for a python object in a module, or None. """ This hook will be called for each Python object in a collected -Python module. The return value is a custom `collection node`_ or None. +Python module. The return value is a custom `collection node`_ or None. -.. XXX or ``False`` if you want to indicate that the given item should not be collected. +.. XXX or ``False`` if you want to indicate that the given item should not be collected. Gateway initialization (distributed testing) @@ -415,32 +415,32 @@ remote environment. For this you can implement the newgateway hook: def pytest_gwmanage_newgateway(gateway, platinfo): """ called after a gateway is instantiated. """ -The ``gateway`` object here has a ``spec`` attribute which is an ``execnet.XSpec`` +The ``gateway`` object here has a ``spec`` attribute which is an ``execnet.XSpec`` object, which has attributes that map key/values as specified from a ``--txspec`` -option. The platinfo object is a dictionary with information about the remote process: +option. The platinfo object is a dictionary with information about the remote process: -* ``version``: remote python's ``sys.version_info`` +* ``version``: remote python's ``sys.version_info`` * ``platform``: remote ``sys.platform`` * ``cwd``: remote ``os.getcwd`` -.. _`collection process`: -.. _`collection node`: +.. _`collection process`: +.. _`collection node`: .. _`test collection`: -Test Collection process -====================================================== +Test Collection process +====================================================== -the collection tree +the collection tree --------------------------------- The collecting process is iterative so that distribution and execution of tests can start as soon as the first test -item is collected. Collection nodes with children are -called "Collectors" and terminal nodes are called "Items". -Here is an example of such a tree, generated with the -command ``py.test --collectonly py/xmlobj``:: +item is collected. Collection nodes with children are +called "Collectors" and terminal nodes are called "Items". +Here is an example of such a tree, generated with the +command ``py.test --collectonly py/xmlobj``:: @@ -457,34 +457,34 @@ command ``py.test --collectonly py/xmlobj``:: -By default all directories not starting with a dot are traversed, -looking for ``test_*.py`` and ``*_test.py`` files. Those Python -files are imported under their `package name`_. +By default all directories not starting with a dot are traversed, +looking for ``test_*.py`` and ``*_test.py`` files. Those Python +files are imported under their `package name`_. -The Module collector looks for test functions +The Module collector looks for test functions and test classes and methods. Test functions and methods -are prefixed ``test`` by default. Test classes must -start with a capitalized ``Test`` prefix. +are prefixed ``test`` by default. Test classes must +start with a capitalized ``Test`` prefix. -Customizing error messages +Customizing error messages ------------------------------------------------- -On test and collection nodes ``py.test`` will invoke +On test and collection nodes ``py.test`` will invoke the ``node.repr_failure(excinfo)`` function which -you may override and make it return an error -representation string of your choice. It -will be reported as a (red) string. +you may override and make it return an error +representation string of your choice. It +will be reported as a (red) string. -.. _`package name`: +.. _`package name`: constructing the package name for test modules ------------------------------------------------- -Test modules are imported under their fully qualified +Test modules are imported under their fully qualified name. Given a filesystem ``fspath`` it is constructed as follows: -* walk the directories up to the last one that contains - an ``__init__.py`` file. +* walk the directories up to the last one that contains + an ``__init__.py`` file. * perform ``sys.path.insert(0, basedir)``. diff --git a/doc/test/examples.txt b/doc/test/examples.txt index 722222e23..d4c905d2a 100644 --- a/doc/test/examples.txt +++ b/doc/test/examples.txt @@ -4,29 +4,29 @@ Learning by examples adding custom options ---------------------- -py.test supports adding of standard optparse_ Options. -A plugin may implement the ``addoption`` hook for registering -custom options:: +py.test supports adding of standard optparse_ Options. +A plugin may implement the ``addoption`` hook for registering +custom options:: def pytest_addoption(parser): - parser.addoption("-M", "--myopt", action="store", + parser.addoption("-M", "--myopt", action="store", help="specify string to set myopt") def pytest_configure(config): if config.option.myopt: # do action based on option value # - + .. _optparse: http://docs.python.org/library/optparse.html Working Examples ================ -managing state at module, class and method level +managing state at module, class and method level ------------------------------------------------------------ -Here is a working example for what goes on when you setup modules, -classes and methods:: +Here is a working example for what goes on when you setup modules, +classes and methods:: # [[from py/documentation/example/pytest/test_setup_flow_example.py]] @@ -58,17 +58,17 @@ For this example the control flow happens as follows:: import test_setup_flow_example setup_module(test_setup_flow_example) - setup_class(TestStateFullThing) + setup_class(TestStateFullThing) instance = TestStateFullThing() - setup_method(instance, instance.test_42) + setup_method(instance, instance.test_42) instance.test_42() - setup_method(instance, instance.test_23) + setup_method(instance, instance.test_23) instance.test_23() - teardown_class(TestStateFullThing) + teardown_class(TestStateFullThing) teardown_module(test_setup_flow_example) -Note that ``setup_class(TestStateFullThing)`` is called and not +Note that ``setup_class(TestStateFullThing)`` is called and not ``TestStateFullThing.setup_class()`` which would require you to insert ``setup_class = classmethod(setup_class)`` to make your setup function callable. Did we mention that lazyness -is a virtue? +is a virtue? diff --git a/doc/test/features.txt b/doc/test/features.txt index 02c67598a..30eca27f4 100644 --- a/doc/test/features.txt +++ b/doc/test/features.txt @@ -1,35 +1,35 @@ ================================================== -py.test feature overview +py.test feature overview ================================================== -.. contents:: +.. contents:: :local: :depth: 1 -mature command line testing tool +mature command line testing tool ==================================================== py.test is a command line tool to collect, run and report about automated tests. It runs well on Linux, Windows and OSX and on Python 2.4 through to 3.1 versions. -It is used in many projects, ranging from running 10 thousands of tests +It is used in many projects, ranging from running 10 thousands of tests to a few inlined tests on a command line script. As of version 1.2 you can also generate a no-dependency py.test-equivalent standalone script that you -can distribute along with your application. +can distribute along with your application. -extensive easy plugin system +extensive easy plugin system ====================================================== .. _`suprisingly easy`: http://bruynooghe.blogspot.com/2009/12/skipping-slow-test-by-default-in-pytest.html py.test delegates almost all aspects of its operation to plugins_. It is `suprisingly easy`_ to add command line options or -do other kind of add-ons and customizations. This can -be done per-project or by distributing a global plugin. -One can can thus modify or add aspects for purposes such as: +do other kind of add-ons and customizations. This can +be done per-project or by distributing a global plugin. +One can can thus modify or add aspects for purposes such as: * reporting extensions -* customizing collection and execution of tests +* customizing collection and execution of tests * running and managing non-python tests -* managing domain-specific test state setup +* managing domain-specific test state setup * adding non-python tests into the run, e.g. driven by data files .. _`plugins`: plugin/index.html @@ -42,18 +42,18 @@ distributing tests to your CPUs and SSH accounts Through the use of the separately released `pytest-xdist`_ plugin you can seemlessly distribute runs to multiple CPUs or remote computers through SSH and sockets. This plugin also offers a ``--looponfailing`` -mode which will continously re-run only failing tests in a subprocess. +mode which will continously re-run only failing tests in a subprocess. -supports several testing practises and methods +supports several testing practises and methods ================================================================== -py.test supports many testing methods conventionally used in -the Python community. It runs traditional `unittest.py`_, +py.test supports many testing methods conventionally used in +the Python community. It runs traditional `unittest.py`_, `doctest.py`_, supports `xUnit style setup`_ and nose_ specific -setups and test suites. It offers minimal no-boilerplate model -for configuring and deploying tests written as simple Python +setups and test suites. It offers minimal no-boilerplate model +for configuring and deploying tests written as simple Python functions or methods. It also integrates `coverage testing -with figleaf`_ or `Javasript unit- and functional testing`_. +with figleaf`_ or `Javasript unit- and functional testing`_. .. _`Javasript unit- and functional testing`: plugin/oejskit.html .. _`coverage testing with figleaf`: plugin/figleaf.html @@ -63,98 +63,98 @@ integrates well with CI systems py.test can produce JUnitXML style output as well as formatted "resultlog" files that can be postprocessed by Continous Integration -systems such as Hudson or Buildbot easily. It also provides command -line options to control test configuration lookup behaviour or ignoring -certain tests or directories. +systems such as Hudson or Buildbot easily. It also provides command +line options to control test configuration lookup behaviour or ignoring +certain tests or directories. -no-boilerplate test functions with Python +no-boilerplate test functions with Python =================================================== .. _`autocollect`: -automatic Python test discovery +automatic Python test discovery ------------------------------------ -By default, all python modules with a ``test_*.py`` +By default, all python modules with a ``test_*.py`` filename are inspected for finding tests: * functions with a name beginning with ``test_`` -* classes with a leading ``Test`` name and ``test`` prefixed methods. +* classes with a leading ``Test`` name and ``test`` prefixed methods. * ``unittest.TestCase`` subclasses parametrizing test functions and functional testing -------------------------------------------------------------- py.test offers the unique `funcargs mechanism`_ for setting up -and passing project-specific objects to Python test functions. -Test Parametrization happens by triggering a call to the same test -function with different argument values. For doing fixtures -using the funcarg mechanism makes your test and setup code +and passing project-specific objects to Python test functions. +Test Parametrization happens by triggering a call to the same test +function with different argument values. For doing fixtures +using the funcarg mechanism makes your test and setup code more efficient and more readable. This is especially true for functional tests which might depend on command line -options and a setup that needs to be shared across -a whole test run. +options and a setup that needs to be shared across +a whole test run. per-test capturing of output, including subprocesses ---------------------------------------------------- -By default, ``py.test`` captures all writes to stdout/stderr. -Output from ``print`` statements as well as from subprocesses -is captured_. When a test fails, the associated captured outputs are shown. +By default, ``py.test`` captures all writes to stdout/stderr. +Output from ``print`` statements as well as from subprocesses +is captured_. When a test fails, the associated captured outputs are shown. This allows you to put debugging print statements in your code without being overwhelmed by all the output that might be generated by tests that do not fail. -.. _captured: plugin/capture.html +.. _captured: plugin/capture.html assert with the ``assert`` statement ---------------------------------------- ``py.test`` allows to use the standard python -``assert statement`` for verifying expectations -and values in Python tests. For example, you can -write the following in your tests:: +``assert statement`` for verifying expectations +and values in Python tests. For example, you can +write the following in your tests:: - assert hasattr(x, 'attribute') + assert hasattr(x, 'attribute') to state that your object has a certain ``attribute``. In case this assertion fails you will see the value of ``x``. Intermediate -values are computed by executing the assert expression a second time. +values are computed by executing the assert expression a second time. If you execute code with side effects, e.g. read from a file like this:: assert f.read() != '...' then you may get a warning from pytest if that assertions -first failed and then succeeded. +first failed and then succeeded. -asserting expected exceptions +asserting expected exceptions ---------------------------------------- In order to write assertions about exceptions, you can use -``py.test.raises`` as a context manager like this: +``py.test.raises`` as a context manager like this: -.. sourcecode:: python +.. sourcecode:: python with py.test.raises(ZeroDivisionError): 1 / 0 and if you need to have access to the actual exception info you may use: -.. sourcecode:: python +.. sourcecode:: python - with py.test.raises(RuntimeError) as excinfo: + with py.test.raises(RuntimeError) as excinfo: def f(): f() f() - # do checks related to excinfo.type, excinfo.value, excinfo.traceback + # do checks related to excinfo.type, excinfo.value, excinfo.traceback -If you want to write test code that works on Python2.4 as well, +If you want to write test code that works on Python2.4 as well, you may also use two other ways to test for an expected exception: -.. sourcecode:: python +.. sourcecode:: python - py.test.raises(ExpectedException, func, *args, **kwargs) + py.test.raises(ExpectedException, func, *args, **kwargs) py.test.raises(ExpectedException, "func(*args, **kwargs)") both of which execute the specified function with args and kwargs and @@ -175,21 +175,21 @@ from nightly runs, i.e. are detached from the actual test running session. Here are `example tracebacks`_ for a number of failing test functions. You can modify traceback printing styles through the command line. Using the `--pdb`` option you can automatically activate -a PDB `Python debugger`_ when a test fails. +a PDB `Python debugger`_ when a test fails. -skip or expect-to-fail a test +skip or expect-to-fail a test ====================================== py.test has a dedicated `skipping plugin`_ that allows to define -* define "skip" outcomes indicating a platform or a - dependency mismatch. +* define "skip" outcomes indicating a platform or a + dependency mismatch. -* "xfail" outcomes indicating an "expected failure" either with - with or without running a test. +* "xfail" outcomes indicating an "expected failure" either with + with or without running a test. * skip and xfail outcomes can be applied at module, class or method - level or even only for certain argument sets of a parametrized function. + level or even only for certain argument sets of a parametrized function. .. _`skipping plugin`: plugin/skipping.html .. _`funcargs mechanism`: funcargs.html @@ -198,52 +198,52 @@ py.test has a dedicated `skipping plugin`_ that allows to define .. _`xUnit style setup`: xunit_setup.html .. _`pytest_nose`: plugin/nose.html -select tests by keyword / test name search +select tests by keyword / test name search ========================================================= -.. _`selection by keyword`: +.. _`selection by keyword`: -You can selectively run tests by specifiying a keyword +You can selectively run tests by specifiying a keyword on the command line. Examples:: - py.test -k test_simple + py.test -k test_simple py.test -k "-test_simple" will run all tests matching (or not matching) the -"test_simple" keyword. Note that you need to quote -the keyword if "-" is recognized as an indicator +"test_simple" keyword. Note that you need to quote +the keyword if "-" is recognized as an indicator for a commandline option. Lastly, you may use:: py.test. -k "test_simple:" -which will run all tests after the expression has *matched once*, i.e. -all tests that are seen after a test that matches the "test_simple" -keyword. +which will run all tests after the expression has *matched once*, i.e. +all tests that are seen after a test that matches the "test_simple" +keyword. By default, all filename parts and class/function names of a test function are put into the set -of keywords for a given test. You can specify additional +of keywords for a given test. You can specify additional kewords like this: -.. sourcecode:: python +.. sourcecode:: python - @py.test.mark.webtest + @py.test.mark.webtest def test_send_http(): - ... + ... and then use those keywords to select tests. See the `pytest_keyword`_ -plugin for more information. +plugin for more information. .. _`pytest_keyword`: plugin/mark.html -Looping on the failing test set +Looping on the failing test set ======================================= ``py.test --looponfailing`` (implemented through the external -`pytest-xdist`_ plugin) allows to run a test suite, +`pytest-xdist`_ plugin) allows to run a test suite, memorize all failures and then loop over the failing set of tests until they all pass. It will re-start running -the tests when it detects file changes in your project. +the tests when it detects file changes in your project. .. _`reStructured Text`: http://docutils.sourceforge.net diff --git a/doc/test/funcargs.txt b/doc/test/funcargs.txt index d0b8e9e15..39523f97d 100644 --- a/doc/test/funcargs.txt +++ b/doc/test/funcargs.txt @@ -2,36 +2,36 @@ **funcargs**: advanced test fixtures and parametrization ============================================================== -.. contents:: +.. contents:: :local: :depth: 2 -what is a "funcarg"? +what is a "funcarg"? ================================================= -A *funcarg* is the short name for "test function argument". Each python test function invocation may receive one or multiple function arguments. Function argument values can be created next to the test code or in separate test configuration files which allows test functions to remain ignorant of how its base test values are created. A test function can also be called multiple times with different sets of function arguments, allowing for arbitrary parametrization. A Funcarg parameter can be any value, a simple number or an application object. +A *funcarg* is the short name for "test function argument". Each python test function invocation may receive one or multiple function arguments. Function argument values can be created next to the test code or in separate test configuration files which allows test functions to remain ignorant of how its base test values are created. A test function can also be called multiple times with different sets of function arguments, allowing for arbitrary parametrization. A Funcarg parameter can be any value, a simple number or an application object. .. _`contact possibilities`: ../contact.html -.. _`parametrizing tests, generalized`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ +.. _`parametrizing tests, generalized`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ .. _`blog post about the monkeypatch funcarg`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ -.. _`xUnit style`: xunit_setup.html +.. _`xUnit style`: xunit_setup.html .. _`funcarg factory`: .. _factory: - -funcarg factories: creating test function arguments + +funcarg factories: creating test function arguments ============================================================== -Test functions can specify one ore more arguments ("funcargs") +Test functions can specify one ore more arguments ("funcargs") and a test module or plugin can define factory functions that provide -the function argument. Let's look at a simple self-contained -example that you can put into a test module: +the function argument. Let's look at a simple self-contained +example that you can put into a test module: .. sourcecode:: python - # ./test_simplefactory.py + # ./test_simplefactory.py def pytest_funcarg__myfuncarg(request): return 42 @@ -62,65 +62,65 @@ If you run this with ``py.test test_simplefactory.py`` you see something like th This means that the test function was called with a ``myfuncarg`` value -of ``42`` and the assert fails accordingly. Here is how py.test -calls the test function: +of ``42`` and the assert fails accordingly. Here is how py.test +calls the test function: -1. py.test discovers the ``test_function`` because of the ``test_`` prefix. - The test function needs a function argument named ``myfuncarg``. - A matching factory function is discovered by looking for the - name ``pytest_funcarg__myfuncarg``. +1. py.test discovers the ``test_function`` because of the ``test_`` prefix. + The test function needs a function argument named ``myfuncarg``. + A matching factory function is discovered by looking for the + name ``pytest_funcarg__myfuncarg``. -2. ``pytest_funcarg__myfuncarg(request)`` is called and - returns the value for ``myfuncarg``. +2. ``pytest_funcarg__myfuncarg(request)`` is called and + returns the value for ``myfuncarg``. -3. ``test_function(42)`` call is executed. +3. ``test_function(42)`` call is executed. Note that if you misspell a function argument or want -to use one that isn't available, you'll see an error -with a list of available function arguments. You can +to use one that isn't available, you'll see an error +with a list of available function arguments. You can also issue:: py.test --funcargs test_simplefactory.py to see available function arguments (which you can also -think of as "resources"). +think of as "resources"). -Factory functions receive a `request object`_ -which they can use to register setup/teardown -functions or access meta data about a test. +Factory functions receive a `request object`_ +which they can use to register setup/teardown +functions or access meta data about a test. -.. _`request object`: +.. _`request object`: funcarg factory request objects ------------------------------------------ -Request objects represents a handle on a specific python test function call. A request object is passed to a funcarg factory and provides access to test configuration and context as well as some `useful caching and finalization helpers`_. Here is a list of attributes: +Request objects represents a handle on a specific python test function call. A request object is passed to a funcarg factory and provides access to test configuration and context as well as some `useful caching and finalization helpers`_. Here is a list of attributes: ``request.function``: python function object requesting the argument -``request.cls``: class object where the test function is defined in or None. +``request.cls``: class object where the test function is defined in or None. -``request.module``: module object where the test function is defined in. +``request.module``: module object where the test function is defined in. ``request.config``: access to command line opts and general config ``request.param``: if exists was passed by a previous `metafunc.addcall`_ -.. _`useful caching and finalization helpers`: +.. _`useful caching and finalization helpers`: -registering funcarg related finalizers/cleanup +registering funcarg related finalizers/cleanup ---------------------------------------------------- -.. sourcecode:: python +.. sourcecode:: python def addfinalizer(func): - """ call a finalizer function when test function finishes. """ - -Calling ``request.addfinalizer()`` is useful for scheduling teardown -functions. Here is an example for providing a ``myfile`` -object that is to be closed when the execution of a -test function finishes. + """ call a finalizer function when test function finishes. """ + +Calling ``request.addfinalizer()`` is useful for scheduling teardown +functions. Here is an example for providing a ``myfile`` +object that is to be closed when the execution of a +test function finishes. .. sourcecode:: python @@ -133,85 +133,85 @@ test function finishes. managing fixtures across test modules and test runs ---------------------------------------------------------- -.. sourcecode:: python +.. sourcecode:: python def cached_setup(setup, teardown=None, scope="module", extrakey=None): - """ cache and return result of calling setup(). + """ cache and return result of calling setup(). - The requested argument name, the scope and the ``extrakey`` - determine the cache key. The scope also determines when - teardown(result) will be called. valid scopes are: - scope == 'function': when the single test function run finishes. + The requested argument name, the scope and the ``extrakey`` + determine the cache key. The scope also determines when + teardown(result) will be called. valid scopes are: + scope == 'function': when the single test function run finishes. scope == 'module': when tests in a different module are run - scope == 'session': when tests of the session have run. + scope == 'session': when tests of the session have run. """ -Calling ``request.cached_setup()`` helps you to manage fixture -objects across several scopes. For example, for creating a Database object +Calling ``request.cached_setup()`` helps you to manage fixture +objects across several scopes. For example, for creating a Database object that is to be setup only once during a test session you can use the helper like this: -.. sourcecode:: python - +.. sourcecode:: python + def pytest_funcarg__database(request): return request.cached_setup( - setup=lambda: Database("..."), - teardown=lambda val: val.close(), + setup=lambda: Database("..."), + teardown=lambda val: val.close(), scope="session" ) dynamically applying a marker --------------------------------------------- -.. sourcecode:: python +.. sourcecode:: python def applymarker(self, marker): - """ apply a marker to a test function invocation. + """ apply a marker to a test function invocation. - The 'marker' must be created with py.test.mark.* XYZ. + The 'marker' must be created with py.test.mark.* XYZ. """ ``request.applymarker(marker)`` will mark the test invocation -with the given marker. For example, if your funcarg factory provides +with the given marker. For example, if your funcarg factory provides values which may cause a test function to fail you can call ``request.applymarker(py.test.mark.xfail(reason='flaky config'))`` and this will cause the test to not show tracebacks. See xfail_ -for details. +for details. .. _`xfail`: plugin/skipping.html#xfail -requesting values of other funcargs +requesting values of other funcargs --------------------------------------------- -.. sourcecode:: python - - def getfuncargvalue(name): - """ Lookup and call function argument factory for the given name. - Each function argument is only created once per function setup. - """ - -``request.getfuncargvalue(name)`` calls another funcarg factory function. -You can use this function if you want to `decorate a funcarg`_, i.e. -you want to provide the "normal" value but add something -extra. If a factory cannot be found a ``request.Error`` -exception will be raised. - -.. _`test generators`: -.. _`parametrizing-tests`: - -generating parametrized tests -=========================================================== - -You can parametrize multiple runs of the same test -function by adding new test function calls with different -function argument values. Let's look at a simple self-contained -example: - .. sourcecode:: python - # ./test_example.py + def getfuncargvalue(name): + """ Lookup and call function argument factory for the given name. + Each function argument is only created once per function setup. + """ + +``request.getfuncargvalue(name)`` calls another funcarg factory function. +You can use this function if you want to `decorate a funcarg`_, i.e. +you want to provide the "normal" value but add something +extra. If a factory cannot be found a ``request.Error`` +exception will be raised. + +.. _`test generators`: +.. _`parametrizing-tests`: + +generating parametrized tests +=========================================================== + +You can parametrize multiple runs of the same test +function by adding new test function calls with different +function argument values. Let's look at a simple self-contained +example: + +.. sourcecode:: python + + # ./test_example.py def pytest_generate_tests(metafunc): - if "numiter" in metafunc.funcargnames: + if "numiter" in metafunc.funcargnames: for i in range(10): metafunc.addcall(funcargs=dict(numiter=i)) @@ -243,108 +243,108 @@ If you run this with ``py.test test_example.py`` you'll get: Here is what happens in detail: 1. ``pytest_generate_tests(metafunc)`` hook is called once for each test - function. It adds ten new function calls with explicit function arguments. + function. It adds ten new function calls with explicit function arguments. -2. **execute tests**: ``test_func(numiter)`` is called ten times with - ten different arguments. +2. **execute tests**: ``test_func(numiter)`` is called ten times with + ten different arguments. .. _`metafunc object`: test generators and metafunc objects ------------------------------------------- -metafunc objects are passed to the ``pytest_generate_tests`` hook. -They help to inspect a testfunction and to generate tests -according to test configuration or values specified -in the class or module where a test function is defined: +metafunc objects are passed to the ``pytest_generate_tests`` hook. +They help to inspect a testfunction and to generate tests +according to test configuration or values specified +in the class or module where a test function is defined: ``metafunc.funcargnames``: set of required function arguments for given function -``metafunc.function``: underlying python test function +``metafunc.function``: underlying python test function -``metafunc.cls``: class object where the test function is defined in or None. +``metafunc.cls``: class object where the test function is defined in or None. -``metafunc.module``: the module object where the test function is defined in. +``metafunc.module``: the module object where the test function is defined in. ``metafunc.config``: access to command line opts and general config -.. _`metafunc.addcall`: +.. _`metafunc.addcall`: -the ``metafunc.addcall()`` method +the ``metafunc.addcall()`` method ----------------------------------------------- .. sourcecode:: python def addcall(funcargs={}, id=None, param=None): - """ trigger a new test function call. """ + """ trigger a new test function call. """ ``funcargs`` can be a dictionary of argument names -mapped to values - providing it is called *direct parametrization*. +mapped to values - providing it is called *direct parametrization*. If you provide an `id`` it will be used for reporting -and identification purposes. If you don't supply an `id` -the stringified counter of the list of added calls will be used. -``id`` values needs to be unique between all -invocations for a given test function. +and identification purposes. If you don't supply an `id` +the stringified counter of the list of added calls will be used. +``id`` values needs to be unique between all +invocations for a given test function. -``param`` if specified will be seen by any -`funcarg factory`_ as a ``request.param`` attribute. -Setting it is called *indirect parametrization*. +``param`` if specified will be seen by any +`funcarg factory`_ as a ``request.param`` attribute. +Setting it is called *indirect parametrization*. -Indirect parametrization is preferable if test values are -expensive to setup or can only be created in certain environments. -Test generators and thus ``addcall()`` invocations are performed -during test collection which is separate from the actual test -setup and test run phase. With distributed testing collection -and test setup/run happens in different process. +Indirect parametrization is preferable if test values are +expensive to setup or can only be created in certain environments. +Test generators and thus ``addcall()`` invocations are performed +during test collection which is separate from the actual test +setup and test run phase. With distributed testing collection +and test setup/run happens in different process. -.. _`tutorial examples`: +.. _`tutorial examples`: Tutorial Examples ======================================= -To see how you can implement custom paramtrization schemes, +To see how you can implement custom paramtrization schemes, see e.g. `parametrizing tests, generalized`_ (blog post). To enable creation of test support code that can flexibly -register setup/teardown functions see the `blog post about -the monkeypatch funcarg`_. +register setup/teardown functions see the `blog post about +the monkeypatch funcarg`_. If you find issues or have further suggestions for improving -the mechanism you are welcome to checkout `contact possibilities`_ page. +the mechanism you are welcome to checkout `contact possibilities`_ page. -.. _`application setup tutorial example`: +.. _`application setup tutorial example`: .. _appsetup: application specific test setup and fixtures --------------------------------------------------------- Here is a basic useful step-wise example for handling application -specific test setup. The goal is to have one place where we have the +specific test setup. The goal is to have one place where we have the glue and test support code for bootstrapping and configuring application objects and allow -test modules and test functions to stay ignorant of involved details. +test modules and test functions to stay ignorant of involved details. step 1: use and implement a test/app-specific "mysetup" +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Let's write a simple test function living in a test file ``test_sample.py`` that uses a ``mysetup`` funcarg for accessing test -specific setup. +specific setup. .. sourcecode:: python # ./test_sample.py - def test_answer(mysetup): + def test_answer(mysetup): app = mysetup.myapp() answer = app.question() assert answer == 42 -To run this test py.test needs to find and call a factory to -obtain the required ``mysetup`` function argument. The test -function interacts with the provided application specific setup. +To run this test py.test needs to find and call a factory to +obtain the required ``mysetup`` function argument. The test +function interacts with the provided application specific setup. To provide the ``mysetup`` function argument we write down a factory method in a `local plugin`_ by putting the @@ -352,8 +352,8 @@ following code into a local ``conftest.py``: .. sourcecode:: python - # ./conftest.py - + # ./conftest.py + from myapp import MyApp def pytest_funcarg__mysetup(request): @@ -362,7 +362,7 @@ following code into a local ``conftest.py``: class MySetup: def myapp(self): return MyApp() - + To run the example we represent our application by putting a pseudo MyApp object into ``myapp.py``: .. sourcecode:: python @@ -397,29 +397,29 @@ show this failure: test_sample.py:5: AssertionError ====================== 1 failed in 0.11 seconds ======================= -This means that our ``mysetup`` object was successfully instantiated, +This means that our ``mysetup`` object was successfully instantiated, we asked it to provide an application instance and checking -its ``question`` method resulted in the wrong answer. If you are -confused as to what the concrete question or answers actually mean, -please see here_ :) Otherwise proceed to step 2. +its ``question`` method resulted in the wrong answer. If you are +confused as to what the concrete question or answers actually mean, +please see here_ :) Otherwise proceed to step 2. .. _here: http://uncyclopedia.wikia.com/wiki/The_Hitchhiker's_Guide_to_the_Galaxy .. _`local plugin`: customize.html#local-plugin .. _`tut-cmdlineoption`: -step 2: adding a command line option +step 2: adding a command line option ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ If you provide a "funcarg" from a plugin you can easily make methods -depend on command line options or environment settings. +depend on command line options or environment settings. To add a command line option we update the conftest.py of -the previous example to add a command line option +the previous example to add a command line option and to offer a new mysetup method: .. sourcecode:: python - # ./conftest.py + # ./conftest.py import py from myapp import MyApp @@ -429,11 +429,11 @@ and to offer a new mysetup method: def pytest_addoption(parser): parser.addoption("--ssh", action="store", default=None, help="specify ssh host to run tests with") - + class MySetup: def __init__(self, request): - self.config = request.config + self.config = request.config def myapp(self): return MyApp() @@ -449,13 +449,13 @@ Now any test function can use the ``mysetup.getsshconnection()`` method like thi .. sourcecode:: python - # ./test_ssh.py + # ./test_ssh.py class TestClass: def test_function(self, mysetup): conn = mysetup.getsshconnection() - # work with conn - -Running ``py.test test_ssh.py`` without specifying a command line option will result in a skipped test_function: + # work with conn + +Running ``py.test test_ssh.py`` without specifying a command line option will result in a skipped test_function: .. sourcecode:: python @@ -469,21 +469,21 @@ Running ``py.test test_ssh.py`` without specifying a command line option will re conftest.py:23: [1] Skipped: 'specify ssh host with --ssh' ====================== 1 skipped in 0.11 seconds ====================== -Note especially how the test function could stay clear knowing about how to construct test state values or when to skip and with what message. The test function can concentrate on actual test code and test state factories can interact with execution of tests. +Note especially how the test function could stay clear knowing about how to construct test state values or when to skip and with what message. The test function can concentrate on actual test code and test state factories can interact with execution of tests. -If you specify a command line option like ``py.test --ssh=python.org`` the test will get un-skipped and actually execute. +If you specify a command line option like ``py.test --ssh=python.org`` the test will get un-skipped and actually execute. -.. _`accept example`: +.. _`accept example`: -example: specifying and selecting acceptance tests +example: specifying and selecting acceptance tests -------------------------------------------------------------- .. sourcecode:: python - # ./conftest.py + # ./conftest.py def pytest_option(parser): group = parser.getgroup("myproject") - group.addoption("-A", dest="acceptance", action="store_true", + group.addoption("-A", dest="acceptance", action="store_true", help="run (slow) acceptance tests") def pytest_funcarg__accept(request): @@ -494,13 +494,13 @@ example: specifying and selecting acceptance tests if not request.config.option.acceptance: py.test.skip("specify -A to run acceptance tests") self.tmpdir = request.config.mktemp(request.function.__name__, numbered=True) - + def run(self, cmd): - """ called by test code to execute an acceptance test. """ - self.tmpdir.chdir() + """ called by test code to execute an acceptance test. """ + self.tmpdir.chdir() return py.process.cmdexec(cmd) - + and the actual test function example: .. sourcecode:: python @@ -509,45 +509,45 @@ and the actual test function example: accept.tmpdir.mkdir("somesub") result = accept.run("ls -la") assert "somesub" in result - + If you run this test without specifying a command line option the test will get skipped with an appropriate message. Otherwise -you can start to add convenience and test support methods +you can start to add convenience and test support methods to your AcceptFuncarg and drive running of tools or applications and provide ways to do assertions about -the output. +the output. -.. _`decorate a funcarg`: +.. _`decorate a funcarg`: example: decorating a funcarg in a test module -------------------------------------------------------------- -For larger scale setups it's sometimes useful to decorare -a funcarg just for a particular test module. We can +For larger scale setups it's sometimes useful to decorare +a funcarg just for a particular test module. We can extend the `accept example`_ by putting this in our test module: .. sourcecode:: python def pytest_funcarg__accept(request): - # call the next factory (living in our conftest.py) - arg = request.getfuncargvalue("accept") + # call the next factory (living in our conftest.py) + arg = request.getfuncargvalue("accept") # create a special layout in our tempdir arg.tmpdir.mkdir("special") - return arg + return arg class TestSpecialAcceptance: def test_sometest(self, accept): assert accept.tmpdir.join("special").check() -Our module level factory will be invoked first and it can -ask its request object to call the next factory and then -decorate its result. This mechanism allows us to stay -ignorant of how/where the function argument is provided - -in our example from a `conftest plugin`_. +Our module level factory will be invoked first and it can +ask its request object to call the next factory and then +decorate its result. This mechanism allows us to stay +ignorant of how/where the function argument is provided - +in our example from a `conftest plugin`_. -sidenote: the temporary directory used here are instances of -the `py.path.local`_ class which provides many of the os.path -methods in a convenient way. +sidenote: the temporary directory used here are instances of +the `py.path.local`_ class which provides many of the os.path +methods in a convenient way. .. _`py.path.local`: ../path.html#local .. _`conftest plugin`: customize.html#conftestplugin diff --git a/doc/test/index.txt b/doc/test/index.txt index b17f7fe9e..e2a14bbb7 100644 --- a/doc/test/index.txt +++ b/doc/test/index.txt @@ -1,19 +1,19 @@ ======================================= -py.test documentation index +py.test documentation index ======================================= -features_: overview and discussion of features. +features_: overview and discussion of features. -quickstart_: getting started with writing a simple test. +quickstart_: getting started with writing a simple test. -`talks, tutorials, examples`_: tutorial examples, slides +`talks, tutorials, examples`_: tutorial examples, slides -funcargs_: powerful parametrized test function setup +funcargs_: powerful parametrized test function setup -`plugins`_: list of available plugins with usage examples and feature details. +`plugins`_: list of available plugins with usage examples and feature details. -customize_: configuration, customization, extensions +customize_: configuration, customization, extensions changelog_: history of changes covering last releases diff --git a/doc/test/mission.txt b/doc/test/mission.txt index 07f017b9b..d3e61beee 100644 --- a/doc/test/mission.txt +++ b/doc/test/mission.txt @@ -1,13 +1,13 @@ -Mission +Mission ==================================== -py.test strives to make testing a fun and no-boilerplate effort. +py.test strives to make testing a fun and no-boilerplate effort. The tool is distributed as part of the `py` package which contains supporting APIs that -are also useable independently. The project independent ``py.test`` command line tool helps you to: +are also useable independently. The project independent ``py.test`` command line tool helps you to: -* rapidly collect and run tests -* run unit- or doctests, functional or integration tests +* rapidly collect and run tests +* run unit- or doctests, functional or integration tests * distribute tests to multiple environments -* use local or global plugins for custom test types and setup +* use local or global plugins for custom test types and setup diff --git a/doc/test/plugin/capture.txt b/doc/test/plugin/capture.txt index 1585269a6..f0cf3147d 100644 --- a/doc/test/plugin/capture.txt +++ b/doc/test/plugin/capture.txt @@ -6,27 +6,27 @@ configurable per-test stdout/stderr capturing mechanisms. .. contents:: :local: -This plugin captures stdout/stderr output for each test separately. -In case of test failures this captured output is shown grouped -togtther with the test. +This plugin captures stdout/stderr output for each test separately. +In case of test failures this captured output is shown grouped +togtther with the test. The plugin also provides test function arguments that help to -assert stdout/stderr output from within your tests, see the -`funcarg example`_. +assert stdout/stderr output from within your tests, see the +`funcarg example`_. -Capturing of input/output streams during tests +Capturing of input/output streams during tests --------------------------------------------------- By default ``sys.stdout`` and ``sys.stderr`` are substituted with -temporary streams during the execution of tests and setup/teardown code. -During the whole testing process it will re-use the same temporary +temporary streams during the execution of tests and setup/teardown code. +During the whole testing process it will re-use the same temporary streams allowing to play well with the logging module which easily -takes ownership on these streams. +takes ownership on these streams. -Also, 'sys.stdin' is substituted with a file-like "null" object that +Also, 'sys.stdin' is substituted with a file-like "null" object that does not return any values. This is to immediately error out -on tests that wait on reading something from stdin. +on tests that wait on reading something from stdin. You can influence output capturing mechanisms from the command line:: @@ -39,34 +39,34 @@ If you set capturing values in a conftest file like this:: # conftest.py option_capture = 'fd' -then all tests in that directory will execute with "fd" style capturing. +then all tests in that directory will execute with "fd" style capturing. -sys-level capturing +sys-level capturing ------------------------------------------ -Capturing on 'sys' level means that ``sys.stdout`` and ``sys.stderr`` -will be replaced with in-memory files (``py.io.TextIO`` to be precise) +Capturing on 'sys' level means that ``sys.stdout`` and ``sys.stderr`` +will be replaced with in-memory files (``py.io.TextIO`` to be precise) that capture writes and decode non-unicode strings to a unicode object -(using a default, usually, UTF-8, encoding). +(using a default, usually, UTF-8, encoding). FD-level capturing and subprocesses ------------------------------------------ The ``fd`` based method means that writes going to system level files -based on the standard file descriptors will be captured, for example -writes such as ``os.write(1, 'hello')`` will be captured properly. -Capturing on fd-level will include output generated from -any subprocesses created during a test. +based on the standard file descriptors will be captured, for example +writes such as ``os.write(1, 'hello')`` will be captured properly. +Capturing on fd-level will include output generated from +any subprocesses created during a test. .. _`funcarg example`: Example Usage of the capturing Function arguments --------------------------------------------------- -You can use the `capsys funcarg`_ and `capfd funcarg`_ to +You can use the `capsys funcarg`_ and `capfd funcarg`_ to capture writes to stdout and stderr streams. Using the -funcargs frees your test from having to care about setting/resetting -the old streams and also interacts well with py.test's own +funcargs frees your test from having to care about setting/resetting +the old streams and also interacts well with py.test's own per-test capturing. Here is an example test function: .. sourcecode:: python @@ -79,12 +79,12 @@ per-test capturing. Here is an example test function: assert err == "world\n" print "next" out, err = capsys.readouterr() - assert out == "next\n" + assert out == "next\n" -The ``readouterr()`` call snapshots the output so far - -and capturing will be continued. After the test -function finishes the original streams will -be restored. If you want to capture on +The ``readouterr()`` call snapshots the output so far - +and capturing will be continued. After the test +function finishes the original streams will +be restored. If you want to capture on the filedescriptor level you can use the ``capfd`` function argument which offers the same interface. @@ -94,9 +94,9 @@ argument which offers the same interface. the 'capsys' test function argument ----------------------------------- -captures writes to sys.stdout/sys.stderr and makes -them available successively via a ``capsys.readouterr()`` method -which returns a ``(out, err)`` tuple of captured snapshot strings. +captures writes to sys.stdout/sys.stderr and makes +them available successively via a ``capsys.readouterr()`` method +which returns a ``(out, err)`` tuple of captured snapshot strings. .. _`capfd funcarg`: @@ -104,11 +104,11 @@ which returns a ``(out, err)`` tuple of captured snapshot strings. the 'capfd' test function argument ---------------------------------- -captures writes to file descriptors 1 and 2 and makes -snapshotted ``(out, err)`` string tuples available +captures writes to file descriptors 1 and 2 and makes +snapshotted ``(out, err)`` string tuples available via the ``capsys.readouterr()`` method. If the underlying platform does not have ``os.dup`` (e.g. Jython) tests using -this funcarg will automatically skip. +this funcarg will automatically skip. command line options -------------------- @@ -123,10 +123,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_capture.py`_ plugin source code -2. put it somewhere as ``pytest_capture.py`` into your import path +1. Download `pytest_capture.py`_ plugin source code +2. put it somewhere as ``pytest_capture.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/capturelog.txt b/doc/test/plugin/capturelog.txt index 8ca148e68..0725c39c2 100644 --- a/doc/test/plugin/capturelog.txt +++ b/doc/test/plugin/capturelog.txt @@ -9,10 +9,10 @@ capture output of logging module. Installation ------------ -You can install the `pytest-capturelog pypi`_ package +You can install the `pytest-capturelog pypi`_ package with pip:: - pip install pytest-capturelog + pip install pytest-capturelog or with easy install:: diff --git a/doc/test/plugin/coverage.txt b/doc/test/plugin/coverage.txt index e56ea1048..e22bab43b 100644 --- a/doc/test/plugin/coverage.txt +++ b/doc/test/plugin/coverage.txt @@ -6,7 +6,7 @@ Write and report coverage data with the 'coverage' package. .. contents:: :local: -Original code by Ross Lawley. +Original code by Ross Lawley. Requires Ned Batchelder's excellent coverage: http://nedbatchelder.com/code/coverage/ diff --git a/doc/test/plugin/doctest.txt b/doc/test/plugin/doctest.txt index 192edf96a..9dd742fea 100644 --- a/doc/test/plugin/doctest.txt +++ b/doc/test/plugin/doctest.txt @@ -9,7 +9,7 @@ collect and execute doctests from modules and test files. Usage ------------- -By default all files matching the ``test*.txt`` pattern will +By default all files matching the ``test*.txt`` pattern will be run through the python standard ``doctest`` module. Issue:: py.test --doctest-glob='*.rst' @@ -19,10 +19,10 @@ tests in all python modules (including regular python test modules):: py.test --doctest-modules -You can also make these changes permanent in your project by +You can also make these changes permanent in your project by putting them into a conftest.py file like this:: - # content of conftest.py + # content of conftest.py option_doctestmodules = True option_doctestglob = "*.rst" @@ -39,10 +39,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_doctest.py`_ plugin source code -2. put it somewhere as ``pytest_doctest.py`` into your import path +1. Download `pytest_doctest.py`_ plugin source code +2. put it somewhere as ``pytest_doctest.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/figleaf.txt b/doc/test/plugin/figleaf.txt index f2f5366fe..c2fe6f0b3 100644 --- a/doc/test/plugin/figleaf.txt +++ b/doc/test/plugin/figleaf.txt @@ -14,7 +14,7 @@ after pip or easy_install mediated installation of ``pytest-figleaf`` you can ty py.test --figleaf [...] to enable figleaf coverage in your test run. A default ".figleaf" data file -and "html" directory will be created. You can use ``--fig-data`` +and "html" directory will be created. You can use ``--fig-data`` and ``fig-html`` to modify the paths. command line options diff --git a/doc/test/plugin/genscript.txt b/doc/test/plugin/genscript.txt index ec1d0b05d..f102afe39 100644 --- a/doc/test/plugin/genscript.txt +++ b/doc/test/plugin/genscript.txt @@ -19,10 +19,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_genscript.py`_ plugin source code -2. put it somewhere as ``pytest_genscript.py`` into your import path +1. Download `pytest_genscript.py`_ plugin source code +2. put it somewhere as ``pytest_genscript.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/helpconfig.txt b/doc/test/plugin/helpconfig.txt index 958e944f1..5c307a7bb 100644 --- a/doc/test/plugin/helpconfig.txt +++ b/doc/test/plugin/helpconfig.txt @@ -19,7 +19,7 @@ command line options ``--traceconfig`` trace considerations of conftest.py files. ``--nomagic`` - don't reinterpret asserts, no traceback cutting. + don't reinterpret asserts, no traceback cutting. ``--debug`` generate and show internal debugging information. ``--help-config`` @@ -29,10 +29,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_helpconfig.py`_ plugin source code -2. put it somewhere as ``pytest_helpconfig.py`` into your import path +1. Download `pytest_helpconfig.py`_ plugin source code +2. put it somewhere as ``pytest_helpconfig.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/hooklog.txt b/doc/test/plugin/hooklog.txt index 6463a4b82..68725396a 100644 --- a/doc/test/plugin/hooklog.txt +++ b/doc/test/plugin/hooklog.txt @@ -19,10 +19,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_hooklog.py`_ plugin source code -2. put it somewhere as ``pytest_hooklog.py`` into your import path +1. Download `pytest_hooklog.py`_ plugin source code +2. put it somewhere as ``pytest_hooklog.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/hookspec.txt b/doc/test/plugin/hookspec.txt index 485f4d252..d56501d54 100644 --- a/doc/test/plugin/hookspec.txt +++ b/doc/test/plugin/hookspec.txt @@ -5,202 +5,202 @@ hook specification sourcecode .. sourcecode:: python """ - hook specifications for py.test plugins + hook specifications for py.test plugins """ - + # ------------------------------------------------------------------------- - # Command line and configuration + # Command line and configuration # ------------------------------------------------------------------------- - + def pytest_namespace(): "return dict of name->object which will get stored at py.test. namespace" - + def pytest_addoption(parser): "add optparse-style options via parser.addoption." - + def pytest_addhooks(pluginmanager): "add hooks via pluginmanager.registerhooks(module)" - + def pytest_configure(config): - """ called after command line options have been parsed. - and all plugins and initial conftest files been loaded. + """ 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. """ - + # ------------------------------------------------------------------------- # collection hooks # ------------------------------------------------------------------------- - + def pytest_ignore_collect(path, config): - """ return true value to prevent considering this path for collection. + """ return true value to prevent considering this path for collection. This hook is consulted for all files and directories prior to considering - collection hooks. + collection hooks. """ pytest_ignore_collect.firstresult = True - + def pytest_collect_directory(path, parent): """ return Collection node or None for the given path. """ pytest_collect_directory.firstresult = True - + def pytest_collect_file(path, parent): """ return Collection node or None for the given path. """ - + def pytest_collectstart(collector): """ collector starts collecting. """ - + 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 a collection and return a collection. """ + """ perform a collection and return a collection. """ pytest_make_collect_report.firstresult = True - - # XXX rename to item_collected()? meaning in distribution context? + + # XXX rename to item_collected()? meaning in distribution context? def pytest_itemstart(item, node=None): """ test item gets collected. """ - + # ------------------------------------------------------------------------- # Python test function related hooks # ------------------------------------------------------------------------- - + def pytest_pycollect_makemodule(path, parent): - """ return a Module collector or None for the given path. - This hook will be called for each matching test module path. - The pytest_collect_file hook needs to be used if you want to + """ return a Module collector or None for the given path. + This hook will be called for each matching test module path. + The pytest_collect_file hook needs to be used if you want to create test modules for files that do not match as a test module. """ 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. """ 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 + # generic runtest related hooks # ------------------------------------------------------------------------- - + def pytest_runtest_protocol(item): """ implement fixture, run and report about the given test item. """ pytest_runtest_protocol.firstresult = True - + def pytest_runtest_setup(item): - """ called before pytest_runtest_call(). """ - + """ called before pytest_runtest_call(). """ + def pytest_runtest_call(item): - """ execute test item. """ - + """ execute test item. """ + def pytest_runtest_teardown(item): - """ called after pytest_runtest_call(). """ - + """ called after pytest_runtest_call(). """ + def pytest_runtest_makereport(item, call): """ make a test report for the given item and call outcome. """ pytest_runtest_makereport.firstresult = True - + def pytest_runtest_logreport(report): - """ process item test report. """ - + """ process item test report. """ + # special handling for final teardown - somewhat internal for now def pytest__teardown_final(session): """ called before test session finishes. """ pytest__teardown_final.firstresult = True - + def pytest__teardown_final_logerror(report): - """ called if runtest_teardown_final failed. """ - + """ called if runtest_teardown_final failed. """ + # ------------------------------------------------------------------------- - # test session related hooks + # test session related hooks # ------------------------------------------------------------------------- - + def pytest_sessionstart(session): """ before session.main() is called. """ - + def pytest_sessionfinish(session, exitstatus): """ whole test run finishes. """ - + # ------------------------------------------------------------------------- # hooks for influencing reporting (invoked from pytest_terminal) # ------------------------------------------------------------------------- - + def pytest_report_header(config): """ 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_report_iteminfo(item): """ return (fspath, lineno, name) for the item. the information is used for result display and to sort tests """ pytest_report_iteminfo.firstresult = True - + # ------------------------------------------------------------------------- - # doctest hooks + # doctest hooks # ------------------------------------------------------------------------- - + def pytest_doctest_prepare_content(content): """ return processed content for a given doctest""" pytest_doctest_prepare_content.firstresult = True - - + + # ------------------------------------------------------------------------- - # error handling and internal debugging hooks + # error handling and internal debugging hooks # ------------------------------------------------------------------------- - + def pytest_plugin_registered(plugin, manager): """ a new py lib plugin got registered. """ - + def pytest_plugin_unregistered(plugin): """ a py lib plugin got unregistered. """ - + def pytest_internalerror(excrepr): """ called for internal errors. """ - + def pytest_keyboard_interrupt(excinfo): """ called for keyboard interrupt. """ - + def pytest_trace(category, msg): - """ called for debug info. """ + """ called for debug info. """ hook specification sourcecode ============================= .. sourcecode:: python - + def pytest_gwmanage_newgateway(gateway, platinfo): - """ called on new raw gateway creation. """ - + """ called on new raw gateway creation. """ + def pytest_gwmanage_rsyncstart(source, gateways): """ called before rsyncing a directory to remote gateways takes place. """ - + def pytest_gwmanage_rsyncfinish(source, gateways): """ called after rsyncing a directory to remote gateways takes place. """ - + def pytest_configure_node(node): """ configure node information before it gets instantiated. """ - + def pytest_testnodeready(node): """ Test Node is ready to operate. """ - + def pytest_testnodedown(node, error): """ Test Node is down. """ - + def pytest_rescheduleitems(items): """ reschedule Items from a node that went down. """ diff --git a/doc/test/plugin/junitxml.txt b/doc/test/plugin/junitxml.txt index b063d2a4f..2fd08b32f 100644 --- a/doc/test/plugin/junitxml.txt +++ b/doc/test/plugin/junitxml.txt @@ -21,10 +21,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_junitxml.py`_ plugin source code -2. put it somewhere as ``pytest_junitxml.py`` into your import path +1. Download `pytest_junitxml.py`_ plugin source code +2. put it somewhere as ``pytest_junitxml.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/mark.txt b/doc/test/plugin/mark.txt index e46fd0a3a..e2ab99947 100644 --- a/doc/test/plugin/mark.txt +++ b/doc/test/plugin/mark.txt @@ -7,18 +7,18 @@ generic mechanism for marking python functions. :local: By using the ``py.test.mark`` helper you can instantiate -decorators that will set named meta data on test functions. +decorators that will set named meta data on test functions. -Marking a single function +Marking a single function ---------------------------------------------------- You can "mark" a test function with meta data like this:: @py.test.mark.webtest def test_send_http(): - ... + ... -This will set a "Marker" instance as a function attribute named "webtest". +This will set a "Marker" instance as a function attribute named "webtest". You can also specify parametrized meta data like this:: @py.test.mark.webtest(firefox=30) @@ -39,7 +39,7 @@ and later access it with ``test_receive.webtest.args[0] == 'triangular``. .. _`scoped-marking`: -Marking whole classes or modules +Marking whole classes or modules ---------------------------------------------------- If you are programming with Python2.6 you may use ``py.test.mark`` decorators @@ -53,9 +53,9 @@ with classes to apply markers to all its test methods:: ... This is equivalent to directly applying the decorator to the -two test functions. +two test functions. -To remain compatible with Python2.5 you can also set a +To remain compatible with Python2.5 you can also set a ``pytestmark`` attribute on a TestClass like this:: import py @@ -75,8 +75,8 @@ You can also set a module level marker:: import py pytestmark = py.test.mark.webtest -in which case it will be applied to all functions and -methods defined in the module. +in which case it will be applied to all functions and +methods defined in the module. Using "-k MARKNAME" to select tests ---------------------------------------------------- @@ -90,10 +90,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_mark.py`_ plugin source code -2. put it somewhere as ``pytest_mark.py`` into your import path +1. Download `pytest_mark.py`_ plugin source code +2. put it somewhere as ``pytest_mark.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/monkeypatch.txt b/doc/test/plugin/monkeypatch.txt index b5455a7a3..62a7b1b11 100644 --- a/doc/test/plugin/monkeypatch.txt +++ b/doc/test/plugin/monkeypatch.txt @@ -6,54 +6,54 @@ safely patch object attributes, dicts and environment variables. .. contents:: :local: -Usage +Usage ---------------- -Use the `monkeypatch funcarg`_ to tweak your global test environment -for running a particular test. You can safely set/del an attribute, +Use the `monkeypatch funcarg`_ to tweak your global test environment +for running a particular test. You can safely set/del an attribute, dictionary item or environment variable by respective methods -on the monkeypatch funcarg. If you want e.g. to set an ENV1 variable -and have os.path.expanduser return a particular directory, you can +on the monkeypatch funcarg. If you want e.g. to set an ENV1 variable +and have os.path.expanduser return a particular directory, you can write it down like this: -.. sourcecode:: python +.. sourcecode:: python def test_mytest(monkeypatch): monkeypatch.setenv('ENV1', 'myval') monkeypatch.setattr(os.path, 'expanduser', lambda x: '/tmp/xyz') ... # your test code that uses those patched values implicitely -After the test function finished all modifications will be undone, -because the ``monkeypatch.undo()`` method is registered as a finalizer. +After the test function finished all modifications will be undone, +because the ``monkeypatch.undo()`` method is registered as a finalizer. -``monkeypatch.setattr/delattr/delitem/delenv()`` all -by default raise an Exception if the target does not exist. -Pass ``raising=False`` if you want to skip this check. +``monkeypatch.setattr/delattr/delitem/delenv()`` all +by default raise an Exception if the target does not exist. +Pass ``raising=False`` if you want to skip this check. -prepending to PATH or other environment variables +prepending to PATH or other environment variables --------------------------------------------------------- To prepend a value to an already existing environment parameter: -.. sourcecode:: python +.. sourcecode:: python def test_mypath_finding(monkeypatch): monkeypatch.setenv('PATH', 'x/y', prepend=":") - # in bash language: export PATH=x/y:$PATH + # in bash language: export PATH=x/y:$PATH calling "undo" finalization explicitely ----------------------------------------- At the end of function execution py.test invokes -a teardown hook which undoes all monkeypatch changes. -If you do not want to wait that long you can call +a teardown hook which undoes all monkeypatch changes. +If you do not want to wait that long you can call finalization explicitely:: - monkeypatch.undo() + monkeypatch.undo() This will undo previous changes. This call consumes the undo stack. Calling it a second time has no effect unless -you start monkeypatching after the undo call. +you start monkeypatching after the undo call. .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ @@ -63,30 +63,30 @@ you start monkeypatching after the undo call. the 'monkeypatch' test function argument ---------------------------------------- -The returned ``monkeypatch`` funcarg provides these +The returned ``monkeypatch`` funcarg provides these helper methods to modify objects, dictionaries or os.environ:: - monkeypatch.setattr(obj, name, value, raising=True) + monkeypatch.setattr(obj, name, value, raising=True) monkeypatch.delattr(obj, name, raising=True) - monkeypatch.setitem(mapping, name, value) + monkeypatch.setitem(mapping, name, value) monkeypatch.delitem(obj, name, raising=True) - monkeypatch.setenv(name, value, prepend=False) + monkeypatch.setenv(name, value, prepend=False) monkeypatch.delenv(name, value, raising=True) monkeypatch.syspath_prepend(path) -All modifications will be undone when the requesting -test function finished its execution. The ``raising`` -parameter determines if a KeyError or AttributeError -will be raised if the set/deletion operation has no target. +All modifications will be undone when the requesting +test function finished its execution. The ``raising`` +parameter determines if a KeyError or AttributeError +will be raised if the set/deletion operation has no target. Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_monkeypatch.py`_ plugin source code -2. put it somewhere as ``pytest_monkeypatch.py`` into your import path +1. Download `pytest_monkeypatch.py`_ plugin source code +2. put it somewhere as ``pytest_monkeypatch.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/nose.txt b/doc/test/plugin/nose.txt index 4b15fb627..a0294207b 100644 --- a/doc/test/plugin/nose.txt +++ b/doc/test/plugin/nose.txt @@ -6,8 +6,8 @@ nose-compatibility plugin: allow to run nose test suites natively. .. contents:: :local: -This is an experimental plugin for allowing to run tests written -in 'nosetests style with py.test. +This is an experimental plugin for allowing to run tests written +in 'nosetests style with py.test. Usage ------------- @@ -17,28 +17,28 @@ type:: py.test # instead of 'nosetests' and you should be able to run nose style tests and at the same -time can make full use of py.test's capabilities. +time can make full use of py.test's capabilities. Supported nose Idioms ---------------------- * setup and teardown at module/class/method level -* SkipTest exceptions and markers +* SkipTest exceptions and markers * setup/teardown decorators -* yield-based tests and their setup -* general usage of nose utilities +* yield-based tests and their setup +* general usage of nose utilities Unsupported idioms / issues ---------------------------------- - nose-style doctests are not collected and executed correctly, - also fixtures don't work. + also fixtures don't work. -- no nose-configuration is recognized +- no nose-configuration is recognized -If you find other issues or have suggestions please run:: +If you find other issues or have suggestions please run:: - py.test --pastebin=all + py.test --pastebin=all and send the resulting URL to a py.test contact channel, at best to the mailing list. @@ -47,10 +47,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_nose.py`_ plugin source code -2. put it somewhere as ``pytest_nose.py`` into your import path +1. Download `pytest_nose.py`_ plugin source code +2. put it somewhere as ``pytest_nose.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/oejskit.txt b/doc/test/plugin/oejskit.txt index b71ea544f..5fc6abe57 100644 --- a/doc/test/plugin/oejskit.txt +++ b/doc/test/plugin/oejskit.txt @@ -4,9 +4,9 @@ pytest_oejskit plugin (EXTERNAL) The `oejskit`_ offers a py.test plugin for running Javascript tests in life browers. Running inside the browsers comes with some speed cost, on the other hand it means for example the code is tested against the real-word DOM implementations. The approach enables to write integration tests such that the JavaScript code is tested against server-side Python code mocked as necessary. Any server-side framework that can already be exposed through WSGI (or for which a subset of WSGI can be written to accommodate the jskit own needs) can play along. -For more info and download please visit the `oejskit PyPI`_ page. +For more info and download please visit the `oejskit PyPI`_ page. -.. _`oejskit`: +.. _`oejskit`: .. _`oejskit PyPI`: http://pypi.python.org/pypi/oejskit .. source link 'http://bitbucket.org/pedronis/js-infrastructure/src/tip/pytest_jstests.py', diff --git a/doc/test/plugin/pastebin.txt b/doc/test/plugin/pastebin.txt index f350586ff..944e5cf54 100644 --- a/doc/test/plugin/pastebin.txt +++ b/doc/test/plugin/pastebin.txt @@ -11,15 +11,15 @@ Usage **Creating a URL for each test failure**:: - py.test --pastebin=failed + py.test --pastebin=failed This will submit test run information to a remote Paste service and provide a URL for each failure. You may select tests as usual or add -for example ``-x`` if you only want to send one particular failure. +for example ``-x`` if you only want to send one particular failure. **Creating a URL for a whole test session log**:: - py.test --pastebin=all + py.test --pastebin=all Currently only pasting to the http://paste.pocoo.org service is implemented. @@ -34,10 +34,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_pastebin.py`_ plugin source code -2. put it somewhere as ``pytest_pastebin.py`` into your import path +1. Download `pytest_pastebin.py`_ plugin source code +2. put it somewhere as ``pytest_pastebin.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/pdb.txt b/doc/test/plugin/pdb.txt index 31232ddab..f89f9a0bd 100644 --- a/doc/test/plugin/pdb.txt +++ b/doc/test/plugin/pdb.txt @@ -19,10 +19,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_pdb.py`_ plugin source code -2. put it somewhere as ``pytest_pdb.py`` into your import path +1. Download `pytest_pdb.py`_ plugin source code +2. put it somewhere as ``pytest_pdb.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/recwarn.txt b/doc/test/plugin/recwarn.txt index 5e451201c..fb568c217 100644 --- a/doc/test/plugin/recwarn.txt +++ b/doc/test/plugin/recwarn.txt @@ -6,10 +6,10 @@ helpers for asserting deprecation and other warnings. .. contents:: :local: -Example usage +Example usage --------------------- -You can use the ``recwarn`` funcarg to track +You can use the ``recwarn`` funcarg to track warnings within a test function: .. sourcecode:: python @@ -30,7 +30,7 @@ warning: .. sourcecode:: python import py - + def test_global(): py.test.deprecated_call(myfunction, 17) @@ -43,16 +43,16 @@ the 'recwarn' test function argument Return a WarningsRecorder instance that provides these methods: * ``pop(category=None)``: return last warning matching the category. -* ``clear()``: clear list of warnings +* ``clear()``: clear list of warnings Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_recwarn.py`_ plugin source code -2. put it somewhere as ``pytest_recwarn.py`` into your import path +1. Download `pytest_recwarn.py`_ plugin source code +2. put it somewhere as ``pytest_recwarn.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/restdoc.txt b/doc/test/plugin/restdoc.txt index a907b860e..62d407272 100644 --- a/doc/test/plugin/restdoc.txt +++ b/doc/test/plugin/restdoc.txt @@ -23,10 +23,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_restdoc.py`_ plugin source code -2. put it somewhere as ``pytest_restdoc.py`` into your import path +1. Download `pytest_restdoc.py`_ plugin source code +2. put it somewhere as ``pytest_restdoc.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/resultlog.txt b/doc/test/plugin/resultlog.txt index 731e60bb5..f2cf2511d 100644 --- a/doc/test/plugin/resultlog.txt +++ b/doc/test/plugin/resultlog.txt @@ -6,8 +6,8 @@ non-xml machine-readable logging of test results. .. contents:: :local: -Useful for buildbot integration code. See the `PyPy-test`_ - web page for post-processing. +Useful for buildbot integration code. See the `PyPy-test`_ + web page for post-processing. .. _`PyPy-test`: http://codespeak.net:8099/summary @@ -22,10 +22,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_resultlog.py`_ plugin source code -2. put it somewhere as ``pytest_resultlog.py`` into your import path +1. Download `pytest_resultlog.py`_ plugin source code +2. put it somewhere as ``pytest_resultlog.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/skipping.txt b/doc/test/plugin/skipping.txt index 9abd7d258..a6a37b419 100644 --- a/doc/test/plugin/skipping.txt +++ b/doc/test/plugin/skipping.txt @@ -6,21 +6,21 @@ advanced skipping for python test functions, classes or modules. .. contents:: :local: -With this plugin you can mark test functions for conditional skipping +With this plugin you can mark test functions for conditional skipping or as "xfail", expected-to-fail. Skipping a test will avoid running it while xfail-marked tests will run and result in an inverted outcome: -a pass becomes a failure and a fail becomes a semi-passing one. +a pass becomes a failure and a fail becomes a semi-passing one. -The need for skipping a test is usually connected to a condition. +The need for skipping a test is usually connected to a condition. If a test fails under all conditions then it's probably better -to mark your test as 'xfail'. +to mark your test as 'xfail'. By passing ``-rxs`` to the terminal reporter you will see extra -summary information on skips and xfail-run tests at the end of a test run. +summary information on skips and xfail-run tests at the end of a test run. .. _skipif: -Skipping a single function +Skipping a single function ------------------------------------------- Here is an example for marking a test function to be skipped @@ -30,17 +30,17 @@ when run on a Python3 interpreter:: def test_function(): ... -During test function setup the skipif condition is +During test function setup the skipif condition is evaluated by calling ``eval(expr, namespace)``. The namespace -contains the ``sys`` and ``os`` modules and the test -``config`` object. The latter allows you to skip based +contains the ``sys`` and ``os`` modules and the test +``config`` object. The latter allows you to skip based on a test configuration value e.g. like this:: @py.test.mark.skipif("not config.getvalue('db')") def test_function(...): ... -Create a shortcut for your conditional skip decorator +Create a shortcut for your conditional skip decorator at module level like this:: win32only = py.test.mark.skipif("sys.platform != 'win32'") @@ -50,34 +50,34 @@ at module level like this:: ... -skip groups of test functions +skip groups of test functions -------------------------------------- As with all metadata function marking you can do it at -`whole class- or module level`_. Here is an example +`whole class- or module level`_. Here is an example for skipping all methods of a test class based on platform:: class TestPosixCalls: pytestmark = py.test.mark.skipif("sys.platform == 'win32'") - + def test_function(self): # will not be setup or run under 'win32' platform # The ``pytestmark`` decorator will be applied to each test function. -If your code targets python2.6 or above you can equivalently use +If your code targets python2.6 or above you can equivalently use the skipif decorator on classes:: @py.test.mark.skipif("sys.platform == 'win32'") class TestPosixCalls: - + def test_function(self): # will not be setup or run under 'win32' platform # It is fine in general to apply multiple "skipif" decorators on a single function - this means that if any of the conditions -apply the function will be skipped. +apply the function will be skipped. .. _`whole class- or module level`: mark.html#scoped-marking @@ -87,7 +87,7 @@ mark a test function as **expected to fail** ------------------------------------------------------- You can use the ``xfail`` marker to indicate that you -expect the test to fail:: +expect the test to fail:: @py.test.mark.xfail def test_function(): @@ -116,7 +116,7 @@ imperative xfail from within a test or setup function ------------------------------------------------------ If you cannot declare xfail-conditions at import time -you can also imperatively produce an XFail-outcome from +you can also imperatively produce an XFail-outcome from within test or setup code. Example:: def test_function(): @@ -127,7 +127,7 @@ within test or setup code. Example:: skipping on a missing import dependency -------------------------------------------------- -You can use the following import helper at module level +You can use the following import helper at module level or within a test or test setup function:: docutils = py.test.importorskip("docutils") @@ -144,7 +144,7 @@ imperative skip from within a test or setup function ------------------------------------------------------ If for some reason you cannot declare skip-conditions -you can also imperatively produce a Skip-outcome from +you can also imperatively produce a Skip-outcome from within test or setup code. Example:: def test_function(): @@ -162,10 +162,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_skipping.py`_ plugin source code -2. put it somewhere as ``pytest_skipping.py`` into your import path +1. Download `pytest_skipping.py`_ plugin source code +2. put it somewhere as ``pytest_skipping.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/terminal.txt b/doc/test/plugin/terminal.txt index cf1912300..e60188ccf 100644 --- a/doc/test/plugin/terminal.txt +++ b/doc/test/plugin/terminal.txt @@ -31,10 +31,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_terminal.py`_ plugin source code -2. put it somewhere as ``pytest_terminal.py`` into your import path +1. Download `pytest_terminal.py`_ plugin source code +2. put it somewhere as ``pytest_terminal.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/tmpdir.txt b/doc/test/plugin/tmpdir.txt index b6e74ad04..0e2fba51c 100644 --- a/doc/test/plugin/tmpdir.txt +++ b/doc/test/plugin/tmpdir.txt @@ -23,16 +23,16 @@ return a temporary directory path object unique to each test function invocation, created as a sub directory of the base temporary directory. The returned object is a `py.path.local`_ -path object. +path object. Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_tmpdir.py`_ plugin source code -2. put it somewhere as ``pytest_tmpdir.py`` into your import path +1. Download `pytest_tmpdir.py`_ plugin source code +2. put it somewhere as ``pytest_tmpdir.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/unittest.txt b/doc/test/plugin/unittest.txt index ec699cc13..e962002f2 100644 --- a/doc/test/plugin/unittest.txt +++ b/doc/test/plugin/unittest.txt @@ -9,12 +9,12 @@ automatically discover and run traditional "unittest.py" style tests. Usage ---------------- -This plugin collects and runs Python `unittest.py style`_ tests. -It will automatically collect ``unittest.TestCase`` subclasses +This plugin collects and runs Python `unittest.py style`_ tests. +It will automatically collect ``unittest.TestCase`` subclasses and their ``test`` methods from the test modules of a project -(usually following the ``test_*.py`` pattern). +(usually following the ``test_*.py`` pattern). -This plugin is enabled by default. +This plugin is enabled by default. .. _`unittest.py style`: http://docs.python.org/library/unittest.html @@ -22,10 +22,10 @@ Start improving this plugin in 30 seconds ========================================= -1. Download `pytest_unittest.py`_ plugin source code -2. put it somewhere as ``pytest_unittest.py`` into your import path +1. Download `pytest_unittest.py`_ plugin source code +2. put it somewhere as ``pytest_unittest.py`` into your import path 3. a subsequent ``py.test`` run will use your local version -Checkout customize_, other plugins_ or `get in contact`_. +Checkout customize_, other plugins_ or `get in contact`_. .. include:: links.txt diff --git a/doc/test/plugin/xdist.txt b/doc/test/plugin/xdist.txt index 5f9db2c03..5d05ccc91 100644 --- a/doc/test/plugin/xdist.txt +++ b/doc/test/plugin/xdist.txt @@ -6,24 +6,24 @@ loop on failing tests, distribute test runs to CPUs and hosts. .. contents:: :local: -The `pytest-xdist`_ plugin extends py.test with some unique +The `pytest-xdist`_ plugin extends py.test with some unique test execution modes: * Looponfail: run your tests repeatedly in a subprocess. After each run py.test waits until a file in your project changes and then re-runs the previously failing tests. This is repeated until all tests pass after which again - a full run is performed. + a full run is performed. * Load-balancing: if you have multiple CPUs or hosts you can use - those for a combined test run. This allows to speed up - development or to use special resources of remote machines. + those for a combined test run. This allows to speed up + development or to use special resources of remote machines. * Multi-Platform coverage: you can specify different Python interpreters - or different platforms and run tests in parallel on all of them. + or different platforms and run tests in parallel on all of them. -Before running tests remotely, ``py.test`` efficiently synchronizes your -program source code to the remote place. All test results -are reported back and displayed to your local test session. +Before running tests remotely, ``py.test`` efficiently synchronizes your +program source code to the remote place. All test results +are reported back and displayed to your local test session. You may specify different Python versions and interpreters. .. _`pytest-xdist`: http://pypi.python.org/pypi/pytest-xdist @@ -38,11 +38,11 @@ To send tests to multiple CPUs, type:: py.test -n NUM -Especially for longer running tests or tests requiring -a lot of IO this can lead to considerable speed ups. +Especially for longer running tests or tests requiring +a lot of IO this can lead to considerable speed ups. -Running tests in a Python subprocess +Running tests in a Python subprocess +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ To instantiate a python2.4 sub process and send tests to it, you may type:: @@ -50,51 +50,51 @@ To instantiate a python2.4 sub process and send tests to it, you may type:: py.test -d --tx popen//python=python2.4 This will start a subprocess which is run with the "python2.4" -Python interpreter, found in your system binary lookup path. +Python interpreter, found in your system binary lookup path. If you prefix the --tx option value like this:: --tx 3*popen//python=python2.4 then three subprocesses would be created and tests -will be load-balanced across these three processes. +will be load-balanced across these three processes. Sending tests to remote SSH accounts +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Suppose you have a package ``mypkg`` which contains some +Suppose you have a package ``mypkg`` which contains some tests that you can successfully run locally. And you -have a ssh-reachable machine ``myhost``. Then +have a ssh-reachable machine ``myhost``. Then you can ad-hoc distribute your tests by typing:: py.test -d --tx ssh=myhostpopen --rsyncdir mypkg mypkg -This will synchronize your ``mypkg`` package directory -to an remote ssh account and then locally collect tests -and send them to remote places for execution. +This will synchronize your ``mypkg`` package directory +to an remote ssh account and then locally collect tests +and send them to remote places for execution. -You can specify multiple ``--rsyncdir`` directories -to be sent to the remote side. +You can specify multiple ``--rsyncdir`` directories +to be sent to the remote side. **NOTE:** For py.test to collect and send tests correctly you not only need to make sure all code and tests directories are rsynced, but that any test (sub) directory also has an ``__init__.py`` file because internally py.test references tests as a fully qualified python -module path. **You will otherwise get strange errors** +module path. **You will otherwise get strange errors** during setup of the remote side. Sending tests to remote Socket Servers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Download the single-module `socketserver.py`_ Python program +Download the single-module `socketserver.py`_ Python program and run it like this:: python socketserver.py It will tell you that it starts listening on the default -port. You can now on your home machine specify this +port. You can now on your home machine specify this new socket host with something like this:: py.test -d --tx socket=192.168.1.102:8888 --rsyncdir mypkg mypkg @@ -102,17 +102,17 @@ new socket host with something like this:: .. _`atonce`: -Running tests on many platforms at once +Running tests on many platforms at once +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ The basic command to run tests on multiple platforms is:: - py.test --dist=each --tx=spec1 --tx=spec2 + py.test --dist=each --tx=spec1 --tx=spec2 If you specify a windows host, an OSX host and a Linux -environment this command will send each tests to all +environment this command will send each tests to all platforms - and report back failures from all platforms -at once. The specifications strings use the `xspec syntax`_. +at once. The specifications strings use the `xspec syntax`_. .. _`xspec syntax`: http://codespeak.net/execnet/trunk/basics.html#xspec @@ -123,14 +123,14 @@ at once. The specifications strings use the `xspec syntax`_. Specifying test exec environments in a conftest.py +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Instead of specifying command line options, you can +Instead of specifying command line options, you can put options values in a ``conftest.py`` file like this:: option_tx = ['ssh=myhost//python=python2.5', 'popen//python=python2.5'] option_dist = True Any commandline ``--tx`` specifictions will add to the list of -available execution environments. +available execution environments. Specifying "rsync" dirs in a conftest.py +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -156,11 +156,11 @@ command line options box each test run in a separate process (unix) ``--dist=distmode`` set mode for distributing tests to exec environments. - + each: send each test to each available environment. - + load: send each test to available environment. - + (default) no: run tests inprocess, don't distribute. ``--tx=xspec`` add a test execution environment. some examples: --tx popen//python=python2.5 --tx socket=192.168.1.102:8888 --tx ssh=user@codespeak.net//chdir=testcache diff --git a/doc/test/quickstart.txt b/doc/test/quickstart.txt index 874c6f346..70fc99f2c 100644 --- a/doc/test/quickstart.txt +++ b/doc/test/quickstart.txt @@ -9,13 +9,13 @@ Quickstart If you have the ``easy_install`` tool (otherwise see here_) just type:: - easy_install -U py + easy_install -U py -Now create a file ``test_sample.py`` with the following content: +Now create a file ``test_sample.py`` with the following content: -.. sourcecode:: python +.. sourcecode:: python - # content of test_sample.py + # content of test_sample.py def func(x): return x + 1 def test_answer(): @@ -27,7 +27,7 @@ You can now run the test file like this:: and will see output like this: -.. sourcecode:: python +.. sourcecode:: python =========================== test session starts ============================ python: platform linux2 -- Python 2.6.2 -- pytest-1.1.0 @@ -46,14 +46,14 @@ and will see output like this: test_sample.py:6: AssertionError ========================= 1 failed in 0.08 seconds ========================= -This output contains Python interpreter information, a list of test objects, -a progress report and important details of the failure. +This output contains Python interpreter information, a list of test objects, +a progress report and important details of the failure. **Where to go from here** `features`_: overview and description of test features -`plugins`_: a list of available plugins which each contain usage examples +`plugins`_: a list of available plugins which each contain usage examples `tutorials`_: some blog entries and starting points with code examples diff --git a/doc/test/talks.txt b/doc/test/talks.txt index 6024a4ef6..f756a4e78 100644 --- a/doc/test/talks.txt +++ b/doc/test/talks.txt @@ -1,5 +1,5 @@ ========================== -Talks and Tutorials +Talks and Tutorials ========================== .. _`funcargs`: funcargs.html @@ -10,33 +10,33 @@ tutorial examples and blog postings .. _`tutorial1 repository`: http://bitbucket.org/hpk42/pytest-tutorial1/ .. _`pycon 2010 tutorial PDF`: http://bitbucket.org/hpk42/pytest-tutorial1/raw/tip/pytest-basic.pdf -basic usage and funcargs: +basic usage and funcargs: - `pycon 2010 tutorial PDF`_ and `tutorial1 repository`_ -function arguments: +function arguments: -- `application setup in test functions with funcargs`_ -- `making funcargs dependendent on command line options`_ +- `application setup in test functions with funcargs`_ +- `making funcargs dependendent on command line options`_ - `monkey patching done right`_ (blog post, consult `monkeypatch plugin`_ for actual 1.0 API) - -test parametrization: -- `generating parametrized tests with funcargs`_ -- `test generators and cached setup`_ -- `parametrizing tests, generalized`_ (blog post) -- `putting test-hooks into local or global plugins`_ (blog post) +test parametrization: -distributed testing: +- `generating parametrized tests with funcargs`_ +- `test generators and cached setup`_ +- `parametrizing tests, generalized`_ (blog post) +- `putting test-hooks into local or global plugins`_ (blog post) -- `simultanously test your code on all platforms`_ (blog entry) - -plugin specific examples: +distributed testing: + +- `simultanously test your code on all platforms`_ (blog entry) + +plugin specific examples: - `skipping slow tests by default in py.test`_ (blog entry) -- `many examples in the docs for plugins`_ +- `many examples in the docs for plugins`_ .. _`skipping slow tests by default in py.test`: http://bruynooghe.blogspot.com/2009/12/skipping-slow-test-by-default-in-pytest.html .. _`making funcargs dependendent on command line options`: funcargs.html#tut-cmdlineoption @@ -44,28 +44,28 @@ plugin specific examples: .. _`monkeypatch plugin`: plugin/monkeypatch.html .. _`application setup in test functions with funcargs`: funcargs.html#appsetup .. _`simultanously test your code on all platforms`: http://tetamap.wordpress.com/2009/03/23/new-simultanously-test-your-code-on-all-platforms/ -.. _`monkey patching done right`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ +.. _`monkey patching done right`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ .. _`putting test-hooks into local or global plugins`: http://tetamap.wordpress.com/2009/05/14/putting-test-hooks-into-local-and-global-plugins/ -.. _`parametrizing tests, generalized`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ +.. _`parametrizing tests, generalized`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ .. _`generating parametrized tests with funcargs`: funcargs.html#test-generators .. _`test generators and cached setup`: http://bruynooghe.blogspot.com/2010/06/pytest-test-generators-and-cached-setup.html conference talks and tutorials ---------------------------------------- -- `ep2009-rapidtesting.pdf`_ tutorial slides (July 2009): +- `ep2009-rapidtesting.pdf`_ tutorial slides (July 2009): - - testing terminology + - testing terminology - basic py.test usage, file system layout - - test function arguments (funcargs_) and test fixtures - - existing plugins - - distributed testing + - test function arguments (funcargs_) and test fixtures + - existing plugins + - distributed testing -- `ep2009-pytest.pdf`_ 60 minute py.test talk, highlighting unique features and a roadmap (July 2009) +- `ep2009-pytest.pdf`_ 60 minute py.test talk, highlighting unique features and a roadmap (July 2009) -- `pycon2009-pytest-introduction.zip`_ slides and files, extended version of py.test basic introduction, discusses more options, also introduces old-style xUnit setup, looponfailing and other features. +- `pycon2009-pytest-introduction.zip`_ slides and files, extended version of py.test basic introduction, discusses more options, also introduces old-style xUnit setup, looponfailing and other features. -- `pycon2009-pytest-advanced.pdf`_ contain a slightly older version of funcargs and distributed testing, compared to the EuroPython 2009 slides. +- `pycon2009-pytest-advanced.pdf`_ contain a slightly older version of funcargs and distributed testing, compared to the EuroPython 2009 slides. .. _`ep2009-rapidtesting.pdf`: http://codespeak.net/download/py/ep2009-rapidtesting.pdf .. _`ep2009-pytest.pdf`: http://codespeak.net/download/py/ep2009-pytest.pdf diff --git a/doc/test/xunit_setup.txt b/doc/test/xunit_setup.txt index a79750c7d..28b042a94 100644 --- a/doc/test/xunit_setup.txt +++ b/doc/test/xunit_setup.txt @@ -7,29 +7,29 @@ extended xUnit style setup .. _`unittest plugin`: plugin/unittest.html .. _`xUnit`: http://en.wikipedia.org/wiki/XUnit -Note: +Note: - Since version 1.0 funcargs_ present the new and + Since version 1.0 funcargs_ present the new and more powerful way to manage test setups with larger - test suites. *funcargs* also provide flexible + test suites. *funcargs* also provide flexible `test parametrization`_ which goes way beyond - what you can do with the xUnit setup/teardown-method - patter. + what you can do with the xUnit setup/teardown-method + patter. Python, Java and many other languages have a tradition -of using xUnit_ style testing. This typically +of using xUnit_ style testing. This typically involves the call of a ``setup`` method before a test function is run and ``teardown`` after -it finishes. With ``py.test`` there are three +it finishes. With ``py.test`` there are three scopes for which you can provide setup/teardown -hooks to provide test fixtures: per-module, per-class -and per-method/function. ``py.test`` will -discover and call according methods automatically. +hooks to provide test fixtures: per-module, per-class +and per-method/function. ``py.test`` will +discover and call according methods automatically. -The `unittest plugin`_ also will intregate ``unittest.TestCase`` +The `unittest plugin`_ also will intregate ``unittest.TestCase`` instances into a test run and call respective setup/teardown methods. -All setup/teardown methods are optional. +All setup/teardown methods are optional. The following methods are called at module level if they exist: @@ -37,45 +37,45 @@ The following methods are called at module level if they exist: def setup_module(module): """ setup up any state specific to the execution - of the given module. + of the given module. """ def teardown_module(module): - """ teardown any state that was previously setup - with a setup_module method. + """ teardown any state that was previously setup + with a setup_module method. """ The following hooks are available for test classes: .. sourcecode:: python - def setup_class(cls): + def setup_class(cls): """ setup up any state specific to the execution - of the given class (which usually contains tests). + of the given class (which usually contains tests). """ - def teardown_class(cls): - """ teardown any state that was previously setup + def teardown_class(cls): + """ teardown any state that was previously setup with a call to setup_class. """ def setup_method(self, method): - """ setup up any state tied to the execution of the given - method in a class. setup_method is invoked for every - test method of a class. + """ setup up any state tied to the execution of the given + method in a class. setup_method is invoked for every + test method of a class. """ - def teardown_method(self, method): - """ teardown any state that was previously setup - with a setup_method call. + def teardown_method(self, method): + """ teardown any state that was previously setup + with a setup_method call. """ The last two hooks, ``setup_method`` and ``teardown_method``, are equivalent to ``setUp`` and ``tearDown`` in the Python standard library's `unittest.py module`_. -Note that it possible that setup/teardown pairs are invoked multiple -times per testing process. +Note that it possible that setup/teardown pairs are invoked multiple +times per testing process. .. _`unittest.py module`: http://docs.python.org/library/unittest.html diff --git a/doc/xml.txt b/doc/xml.txt index 21cb8913e..7c4bac68d 100644 --- a/doc/xml.txt +++ b/doc/xml.txt @@ -1,52 +1,52 @@ ==================================================== -py.xml: Lightweight and flexible xml/html generation +py.xml: Lightweight and flexible xml/html generation ==================================================== Motivation ========== -There are a plethora of frameworks and libraries to generate -xml and html trees. However, many of them are large, have a -steep learning curve and are often hard to debug. Not to -speak of the fact that they are frameworks to begin with. +There are a plethora of frameworks and libraries to generate +xml and html trees. However, many of them are large, have a +steep learning curve and are often hard to debug. Not to +speak of the fact that they are frameworks to begin with. The py lib strives to offer enough functionality to represent -itself and especially its API in html or xml. +itself and especially its API in html or xml. .. _xist: http://www.livinglogic.de/Python/xist/index.html -a pythonic object model , please +a pythonic object model , please ================================ -The py lib offers a pythonic way to generate xml/html, based on -ideas from xist_ which `uses python class objects`_ to build -xml trees. However, xist_'s implementation is somewhat heavy -because it has additional goals like transformations and -supporting many namespaces. But its basic idea is very easy. +The py lib offers a pythonic way to generate xml/html, based on +ideas from xist_ which `uses python class objects`_ to build +xml trees. However, xist_'s implementation is somewhat heavy +because it has additional goals like transformations and +supporting many namespaces. But its basic idea is very easy. .. _`uses python class objects`: http://www.livinglogic.de/Python/xist/Howto.html generating arbitrary xml structures ------------------------------------ +----------------------------------- With ``py.xml.Namespace`` you have the basis -to generate custom xml-fragments on the fly:: +to generate custom xml-fragments on the fly:: - class ns(py.xml.Namespace): - "my custom xml namespace" + class ns(py.xml.Namespace): + "my custom xml namespace" doc = ns.books( ns.book( - ns.author("May Day"), - ns.title("python for java programmers"),), - ns.book( - ns.author("why"), + ns.author("May Day"), + ns.title("python for java programmers"),), + ns.book( + ns.author("why"), ns.title("Java for Python programmers"),), - publisher="N.N", + publisher="N.N", ) print doc.unicode(indent=2).encode('utf8') -will give you this representation:: +will give you this representation:: @@ -56,42 +56,42 @@ will give you this representation:: why Java for Python programmers -In a sentence: positional arguments are child-tags and -keyword-arguments are attributes. +In a sentence: positional arguments are child-tags and +keyword-arguments are attributes. On a side note, you'll see that the unicode-serializer supports a nice indentation style which keeps your generated html readable, basically through emulating python's white space significance by putting closing-tags rightmost and -almost invisible at first glance :-) +almost invisible at first glance :-) -basic example for generating html +basic example for generating html --------------------------------- -Consider this example:: +Consider this example:: - from py.xml import html # html namespace + from py.xml import html # html namespace paras = "First Para", "Second para" doc = html.html( html.head( - html.meta(name="Content-Type", value="text/html; charset=latin1")), + html.meta(name="Content-Type", value="text/html; charset=latin1")), html.body( [html.p(p) for p in paras])) print unicode(doc).encode('latin1') -Again, tags are objects which contain tags and have attributes. -More exactly, Tags inherit from the list type and thus can be -manipulated as list objects. They additionally support a default -way to represent themselves as a serialized unicode object. +Again, tags are objects which contain tags and have attributes. +More exactly, Tags inherit from the list type and thus can be +manipulated as list objects. They additionally support a default +way to represent themselves as a serialized unicode object. -If you happen to look at the py.xml implementation you'll -note that the tag/namespace implementation consumes some 50 lines -with another 50 lines for the unicode serialization code. +If you happen to look at the py.xml implementation you'll +note that the tag/namespace implementation consumes some 50 lines +with another 50 lines for the unicode serialization code. -CSS-styling your html Tags +CSS-styling your html Tags -------------------------- One aspect where many of the huge python xml/html generation @@ -100,37 +100,37 @@ of CSS styling. Often, developers are left alone with keeping CSS style definitions in sync with some style files represented as strings (often in a separate .css file). Not only is this hard to debug but the missing abstractions make -it hard to modify the styling of your tags or to choose custom -style representations (inline, html.head or external). Add the -Browers usual tolerance of messyness and errors in Style -references and welcome to hell, known as the domain of -developing web applications :-) +it hard to modify the styling of your tags or to choose custom +style representations (inline, html.head or external). Add the +Browers usual tolerance of messyness and errors in Style +references and welcome to hell, known as the domain of +developing web applications :-) By contrast, consider this CSS styling example:: - class my(html): - "my initial custom style" - class body(html.body): - style = html.Style(font_size = "120%") + class my(html): + "my initial custom style" + class body(html.body): + style = html.Style(font_size = "120%") - class h2(html.h2): - style = html.Style(background = "grey") - - class p(html.p): - style = html.Style(font_weight="bold") + class h2(html.h2): + style = html.Style(background = "grey") + + class p(html.p): + style = html.Style(font_weight="bold") doc = my.html( - my.head(), + my.head(), my.body( - my.h2("hello world"), - my.p("bold as bold can") + my.h2("hello world"), + my.p("bold as bold can") ) ) - - print doc.unicode(indent=2) -This will give you a small'n mean self contained -represenation by default:: + print doc.unicode(indent=2) + +This will give you a small'n mean self contained +represenation by default:: @@ -139,19 +139,19 @@ represenation by default::

bold as bold can

Most importantly, note that the inline-styling is just an -implementation detail of the unicode serialization code. +implementation detail of the unicode serialization code. You can easily modify the serialization to put your styling into the ``html.head`` or in a separate file and autogenerate CSS-class -names or ids. +names or ids. Hey, you could even write tests that you are using correct styles suitable for specific browser requirements. Did i mention -that the ability to easily write tests for your generated -html and its serialization could help to develop _stable_ user -interfaces? +that the ability to easily write tests for your generated +html and its serialization could help to develop _stable_ user +interfaces? -More to come ... ----------------- +More to come ... +---------------- For now, i don't think we should strive to offer much more than the above. However, it is probably not hard to offer @@ -163,6 +163,6 @@ produce a list of unicode objects intermingled with callables. At HTTP-Request time the callables would get called to complete the probably request-specific serialization of your Tags. Hum, it's probably harder to explain this than to -actually code it :-) +actually code it :-) .. _`py.test`: test/index.html diff --git a/hacking/execnet_path.txt b/hacking/execnet_path.txt index f10c88e99..d70d0b03a 100644 --- a/hacking/execnet_path.txt +++ b/hacking/execnet_path.txt @@ -2,25 +2,25 @@ Execnet / Path combination I think the nice code in this directory should be refactored so that you can use -it like this: +it like this: - rp = gateway.get_remote_path(relpath) + rp = gateway.get_remote_path(relpath) and relpath could be absolute, relative (should follow remote-platform syntax) or None/"." (the -current dir on the other side). +current dir on the other side). -The tricky part probably is defining sensible -setup/teardown semantics with respect to -starting the "Path" server on the other side, +The tricky part probably is defining sensible +setup/teardown semantics with respect to +starting the "Path" server on the other side, we at least don't want to have multiple threads that serve path requests and maybe we want to be able to explicitely shutdown a once -started RemotePath server (not sure though). +started RemotePath server (not sure though). For a single-threaded py.execnet it might be helpful to be able to install new network messages (which are lower level than remote_exec() and work with callbacks, so don't follow the nice "synchronous" programming model that you get with -threads/greenlets/tasklets). +threads/greenlets/tasklets). diff --git a/hacking/notes-svn-quoting.txt b/hacking/notes-svn-quoting.txt index a9b49d4e1..3a0432695 100644 --- a/hacking/notes-svn-quoting.txt +++ b/hacking/notes-svn-quoting.txt @@ -24,7 +24,7 @@ URL related notes characters that aren't allowed in URL paths (such as :, @, %, etc.) should be replaced with a % sign following the ASCII value of the character (two digit HEX) - + an exception (the only one I could find so far) is the drive letter in a file URL in windows, the following path was required to get a file 'bar' from a repo in 'c:\\foo':: diff --git a/py/__init__.py b/py/__init__.py index 3116b8660..85e981166 100644 --- a/py/__init__.py +++ b/py/__init__.py @@ -4,7 +4,7 @@ py.test and pylib: rapid testing and development utils this module uses apipkg.py for lazy-loading sub modules and classes. The initpkg-dictionary below specifies name->value mappings where value can be another namespace -dictionary or an import path. +dictionary or an import path. (c) Holger Krekel and others, 2004-2010 """ @@ -137,7 +137,7 @@ py.apipkg.initpkg(__name__, dict( 'StdCapture' : '._io.capture:StdCapture', 'StdCaptureFD' : '._io.capture:StdCaptureFD', 'TerminalWriter' : '._io.terminalwriter:TerminalWriter', - 'ansi_print' : '._io.terminalwriter:ansi_print', + 'ansi_print' : '._io.terminalwriter:ansi_print', 'get_terminal_width' : '._io.terminalwriter:get_terminal_width', 'saferepr' : '._io.saferepr:saferepr', }, diff --git a/py/_builtin.py b/py/_builtin.py index 6ebb9b09f..8b7ca1421 100644 --- a/py/_builtin.py +++ b/py/_builtin.py @@ -67,10 +67,10 @@ except NameError: try: set, frozenset = set, frozenset except NameError: - from sets import set, frozenset + from sets import set, frozenset # pass through -enumerate = enumerate +enumerate = enumerate try: BaseException = BaseException @@ -91,8 +91,8 @@ if sys.version_info >= (3, 0): exec ("print_ = print ; exec_=exec") import builtins - # some backward compatibility helpers - _basestring = str + # some backward compatibility helpers + _basestring = str def _totext(obj, encoding=None): if isinstance(obj, bytes): obj = obj.decode(encoding) @@ -100,9 +100,9 @@ if sys.version_info >= (3, 0): obj = str(obj) return obj - def _isbytes(x): + def _isbytes(x): return isinstance(x, bytes) - def _istext(x): + def _istext(x): return isinstance(x, str) def _getimself(function): @@ -135,13 +135,13 @@ if sys.version_info >= (3, 0): else: import __builtin__ as builtins - _totext = unicode + _totext = unicode _basestring = basestring execfile = execfile callable = callable - def _isbytes(x): + def _isbytes(x): return isinstance(x, str) - def _istext(x): + def _istext(x): return isinstance(x, unicode) def _getimself(function): @@ -157,7 +157,7 @@ else: return getattr(function, "func_code", None) def print_(*args, **kwargs): - """ minimal backport of py3k print statement. """ + """ minimal backport of py3k print statement. """ sep = ' ' if 'sep' in kwargs: sep = kwargs.pop('sep') @@ -177,16 +177,16 @@ else: file.write(end) def exec_(obj, globals=None, locals=None): - """ minimal backport of py3k exec statement. """ + """ minimal backport of py3k exec statement. """ __tracebackhide__ = True - if globals is None: + if globals is None: frame = sys._getframe(1) - globals = frame.f_globals + globals = frame.f_globals if locals is None: locals = frame.f_locals elif locals is None: locals = globals - exec2(obj, globals, locals) + exec2(obj, globals, locals) if sys.version_info >= (3,0): def _reraise(cls, val, tb): @@ -200,11 +200,11 @@ def _reraise(cls, val, tb): raise cls, val, tb def exec2(obj, globals, locals): __tracebackhide__ = True - exec obj in globals, locals + exec obj in globals, locals """) def _tryimport(*names): - """ return the first successfully imported module. """ + """ return the first successfully imported module. """ assert names for name in names: try: diff --git a/py/_cmdline/pycleanup.py b/py/_cmdline/pycleanup.py index 7d35c5c2b..243d7acbe 100755 --- a/py/_cmdline/pycleanup.py +++ b/py/_cmdline/pycleanup.py @@ -1,10 +1,10 @@ -#!/usr/bin/env python +#!/usr/bin/env python """\ py.cleanup [PATH] ... Delete typical python development related files recursively under the specified PATH (which defaults to the current working directory). Don't follow links and don't recurse into directories with a dot. Optionally remove setup.py related files and empty -directories. +directories. """ import py @@ -12,9 +12,9 @@ import sys, subprocess def main(): parser = py.std.optparse.OptionParser(usage=__doc__) - parser.add_option("-e", metavar="ENDING", - dest="endings", default=[".pyc", "$py.class"], action="append", - help=("(multi) recursively remove files with the given ending." + parser.add_option("-e", metavar="ENDING", + dest="endings", default=[".pyc", "$py.class"], action="append", + help=("(multi) recursively remove files with the given ending." " '.pyc' and '$py.class' are in the default list.")) parser.add_option("-d", action="store_true", dest="removedir", help="remove empty directories.") @@ -22,8 +22,8 @@ def main(): help="remove 'build' and 'dist' directories next to setup.py files") parser.add_option("-a", action="store_true", dest="all", help="synonym for '-S -d -e pip-log.txt'") - parser.add_option("-n", "--dryrun", dest="dryrun", default=False, - action="store_true", + parser.add_option("-n", "--dryrun", dest="dryrun", default=False, + action="store_true", help="don't actually delete but display would-be-removed filenames.") (options, args) = parser.parse_args() @@ -44,9 +44,9 @@ class Cleanup: if self.options.setup: for arg in self.args: self.setupclean(arg) - + for path in self.args: - py.builtin.print_("cleaning path", path, + py.builtin.print_("cleaning path", path, "of extensions", self.options.endings) for x in path.visit(self.shouldremove, self.recursedir): self.remove(x) @@ -78,7 +78,7 @@ class Cleanup: subprocess.call([sys.executable, str(setup)] + list(args)) finally: old.chdir() - + def setupclean(self, path): for x in path.visit("setup.py", self.recursedir): basepath = x.dirpath() diff --git a/py/_cmdline/pyconvert_unittest.py b/py/_cmdline/pyconvert_unittest.py index a50233638..500d21892 100644 --- a/py/_cmdline/pyconvert_unittest.py +++ b/py/_cmdline/pyconvert_unittest.py @@ -64,7 +64,7 @@ def blocksplitter(fp): blockstring = line # reset the block else: blockstring += line - + blocklist.append(blockstring) return blocklist @@ -84,7 +84,7 @@ def rewrite_utest(block): op = d[old][1] # the operator you will use , or '' if there is none. possible_args = d[old][2] # a list of the number of arguments the # unittest function could possibly take. - + if possible_args == ['Any']: # just rename assertRaises & friends return re.sub('self.'+old, new, block) @@ -97,7 +97,7 @@ def rewrite_utest(block): except SyntaxError: # but we couldn't parse it! return block - + argnum = len(argl) if argnum not in possible_args: # sanity check - this one isn't real either @@ -132,12 +132,12 @@ def rewrite_utest(block): def decompose_unittest(old, block): '''decompose the block into its component parts''' - ''' returns indent, arglist, trailer + ''' returns indent, arglist, trailer indent -- the indentation arglist -- the arguments to the unittest function trailer -- any extra junk after the closing paren, such as #commment ''' - + indent = re.match(r'(\s*)', block).group() pat = re.search('self.' + old + r'\(', block) @@ -178,7 +178,7 @@ def get_expr(s, char): pos.append(i) if pos == []: raise SyntaxError # we didn't find the expected char. Ick. - + for p in pos: # make the python parser do the hard work of deciding which comma # splits the string into two expressions @@ -248,6 +248,6 @@ def main(): outfile.write(s) - + if __name__ == '__main__': main() diff --git a/py/_cmdline/pycountloc.py b/py/_cmdline/pycountloc.py index 28c0c172f..d4bf4e540 100755 --- a/py/_cmdline/pycountloc.py +++ b/py/_cmdline/pycountloc.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -# hands on script to compute the non-empty Lines of Code -# for tests and non-test code +# hands on script to compute the non-empty Lines of Code +# for tests and non-test code """\ py.countloc [PATHS] @@ -17,18 +17,18 @@ def main(): parser = py.std.optparse.OptionParser(usage=__doc__) (options, args) = parser.parse_args() countloc(args) - + def nodot(p): return p.check(dotfile=0) -class FileCounter(object): +class FileCounter(object): def __init__(self): self.file2numlines = {} self.numlines = 0 self.numfiles = 0 def addrecursive(self, directory, fil="*.py", rec=nodot): - for x in directory.visit(fil, rec): + for x in directory.visit(fil, rec): self.addfile(x) def addfile(self, fn, emptylines=False): @@ -39,21 +39,21 @@ class FileCounter(object): for i in fn.readlines(): if i.strip(): s += 1 - self.file2numlines[fn] = s + self.file2numlines[fn] = s self.numfiles += 1 self.numlines += s - def getnumlines(self, fil): + def getnumlines(self, fil): numlines = 0 for path, value in self.file2numlines.items(): - if fil(path): + if fil(path): numlines += value - return numlines + return numlines - def getnumfiles(self, fil): + def getnumfiles(self, fil): numfiles = 0 for path in self.file2numlines: - if fil(path): + if fil(path): numfiles += 1 return numfiles @@ -61,18 +61,18 @@ def get_loccount(locations=None): if locations is None: localtions = [py.path.local()] counter = FileCounter() - for loc in locations: + for loc in locations: counter.addrecursive(loc, '*.py', rec=nodot) def istestfile(p): return p.check(fnmatch='test_*.py') isnottestfile = lambda x: not istestfile(x) - numfiles = counter.getnumfiles(isnottestfile) - numlines = counter.getnumlines(isnottestfile) + numfiles = counter.getnumfiles(isnottestfile) + numlines = counter.getnumlines(isnottestfile) numtestfiles = counter.getnumfiles(istestfile) numtestlines = counter.getnumlines(istestfile) - + return counter, numfiles, numlines, numtestfiles, numtestlines def countloc(paths=None): @@ -86,7 +86,7 @@ def countloc(paths=None): items.sort(lambda x,y: cmp(x[1], y[1])) for x, y in items: print("%3d %30s" % (y,x)) - + print("%30s %3d" %("number of testfiles", numtestfiles)) print("%30s %3d" %("number of non-empty testlines", numtestlines)) print("%30s %3d" %("number of files", numfiles)) diff --git a/py/_cmdline/pylookup.py b/py/_cmdline/pylookup.py index 369ce90cd..81680b0d9 100755 --- a/py/_cmdline/pylookup.py +++ b/py/_cmdline/pylookup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python """\ py.lookup [search_directory] SEARCH_STRING [options] @@ -65,7 +65,7 @@ def main(): searchlines = s.lower().splitlines() else: searchlines = lines - for i, (line, searchline) in enumerate(zip(lines, searchlines)): + for i, (line, searchline) in enumerate(zip(lines, searchlines)): indexes = find_indexes(searchline, string) if not indexes: continue diff --git a/py/_cmdline/pytest.py b/py/_cmdline/pytest.py index 14e2bc81c..083a5eaa2 100755 --- a/py/_cmdline/pytest.py +++ b/py/_cmdline/pytest.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python import py def main(args=None): diff --git a/py/_cmdline/pywhich.py b/py/_cmdline/pywhich.py index b1b940437..721b30d26 100755 --- a/py/_cmdline/pywhich.py +++ b/py/_cmdline/pywhich.py @@ -1,9 +1,9 @@ -#!/usr/bin/env python +#!/usr/bin/env python """\ py.which [name] -print the location of the given python module or package name +print the location of the given python module or package name """ import sys @@ -16,7 +16,7 @@ def main(): sys.stderr.write("could not import: " + name + "\n") else: try: - location = mod.__file__ + location = mod.__file__ except AttributeError: sys.stderr.write("module (has no __file__): " + str(mod)) else: diff --git a/py/_code/_assertionold.py b/py/_code/_assertionold.py index a472b54b4..6df1d55d3 100644 --- a/py/_code/_assertionold.py +++ b/py/_code/_assertionold.py @@ -496,7 +496,7 @@ def getmsg(excinfo): #frame = py.code.Frame(frame) #return interpret(line, frame) - tb = excinfo.traceback[-1] + tb = excinfo.traceback[-1] source = str(tb.statement).strip() x = interpret(source, tb.frame, should_fail=True) if not isinstance(x, str): diff --git a/py/_code/assertion.py b/py/_code/assertion.py index a2396c542..2a2da9cfb 100644 --- a/py/_code/assertion.py +++ b/py/_code/assertion.py @@ -74,4 +74,4 @@ if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): from py._code._assertionnew import interpret as reinterpret else: reinterpret = reinterpret_old - + diff --git a/py/_code/code.py b/py/_code/code.py index dc765bb36..4e8842b61 100644 --- a/py/_code/code.py +++ b/py/_code/code.py @@ -9,15 +9,15 @@ class Code(object): """ wrapper around Python code objects """ def __init__(self, rawcode): rawcode = py.code.getrawcode(rawcode) - self.raw = rawcode + self.raw = rawcode try: self.filename = rawcode.co_filename self.firstlineno = rawcode.co_firstlineno - 1 self.name = rawcode.co_name - except AttributeError: + except AttributeError: raise TypeError("not a code object: %r" %(rawcode,)) - - def __eq__(self, other): + + def __eq__(self, other): return self.raw == other.raw def __ne__(self, other): @@ -27,11 +27,11 @@ class Code(object): """ return a path object pointing to source code""" p = py.path.local(self.raw.co_filename) if not p.check(): - # XXX maybe try harder like the weird logic - # in the standard lib [linecache.updatecache] does? + # XXX maybe try harder like the weird logic + # in the standard lib [linecache.updatecache] does? p = self.raw.co_filename return p - + path = property(path, None, None, "path of this code object") def fullsource(self): @@ -42,7 +42,7 @@ class Code(object): return full fullsource = property(fullsource, None, None, "full source containing this code object") - + def source(self): """ return a py.code.Source object for the code object's source only """ @@ -81,7 +81,7 @@ class Frame(object): returns the result of the evaluation """ - f_locals = self.f_locals.copy() + f_locals = self.f_locals.copy() f_locals.update(vars) return eval(code, self.f_globals, f_locals) @@ -90,7 +90,7 @@ class Frame(object): 'vars' are optiona; additional local variables """ - f_locals = self.f_locals.copy() + f_locals = self.f_locals.copy() f_locals.update(vars) py.builtin.exec_(code, self.f_globals, f_locals ) @@ -115,8 +115,8 @@ class Frame(object): class TracebackEntry(object): """ a single entry in a traceback """ - - exprinfo = None + + exprinfo = None def __init__(self, rawentry): self._rawentry = rawentry @@ -153,13 +153,13 @@ class TracebackEntry(object): x = py.code._reinterpret(source, self.frame, should_fail=True) if not isinstance(x, str): raise TypeError("interpret returned non-string %r" % (x,)) - self.exprinfo = x + self.exprinfo = x return self.exprinfo def getfirstlinesource(self): return self.frame.code.firstlineno - def getsource(self): + def getsource(self): """ return failing source code. """ source = self.frame.code.fullsource if source is None: @@ -167,64 +167,64 @@ class TracebackEntry(object): start = self.getfirstlinesource() end = self.lineno try: - _, end = source.getstatementrange(end) - except IndexError: - end = self.lineno + 1 - # heuristic to stop displaying source on e.g. + _, end = source.getstatementrange(end) + except IndexError: + end = self.lineno + 1 + # heuristic to stop displaying source on e.g. # if something: # assume this causes a NameError - # # _this_ lines and the one - # below we don't want from entry.getsource() - for i in range(self.lineno, end): - if source[i].rstrip().endswith(':'): + # # _this_ lines and the one + # below we don't want from entry.getsource() + for i in range(self.lineno, end): + if source[i].rstrip().endswith(':'): end = i + 1 - break + break return source[start:end] source = property(getsource) def ishidden(self): - """ return True if the current frame has a var __tracebackhide__ + """ return True if the current frame has a var __tracebackhide__ resolving to True - + mostly for internal use """ - try: - return self.frame.eval("__tracebackhide__") - except (SystemExit, KeyboardInterrupt): + try: + return self.frame.eval("__tracebackhide__") + except (SystemExit, KeyboardInterrupt): raise except: - return False + return False - def __str__(self): - try: - fn = str(self.path) - except py.error.Error: + def __str__(self): + try: + fn = str(self.path) + except py.error.Error: fn = '???' - name = self.frame.code.name - try: + name = self.frame.code.name + try: line = str(self.statement).lstrip() except KeyboardInterrupt: raise except: line = "???" - return " File %r:%d in %s\n %s\n" %(fn, self.lineno+1, name, line) + return " File %r:%d in %s\n %s\n" %(fn, self.lineno+1, name, line) def name(self): return self.frame.code.raw.co_name name = property(name, None, None, "co_name of underlaying code") class Traceback(list): - """ Traceback objects encapsulate and offer higher level - access to Traceback entries. + """ Traceback objects encapsulate and offer higher level + access to Traceback entries. """ - Entry = TracebackEntry + Entry = TracebackEntry def __init__(self, tb): """ initialize from given python traceback object. """ if hasattr(tb, 'tb_next'): - def f(cur): - while cur is not None: + def f(cur): + while cur is not None: yield self.Entry(cur) - cur = cur.tb_next - list.__init__(self, f(tb)) + cur = cur.tb_next + list.__init__(self, f(tb)) else: list.__init__(self, tb) @@ -243,7 +243,7 @@ class Traceback(list): codepath = code.path if ((path is None or codepath == path) and (excludepath is None or not hasattr(codepath, 'relto') or - not codepath.relto(excludepath)) and + not codepath.relto(excludepath)) and (lineno is None or x.lineno == lineno) and (firstlineno is None or x.frame.code.firstlineno == firstlineno)): return Traceback(x._rawentry) @@ -269,7 +269,7 @@ class Traceback(list): def getcrashentry(self): """ return last non-hidden traceback entry that lead - to the exception of a traceback. + to the exception of a traceback. """ tb = self.filter() if not tb: @@ -282,17 +282,17 @@ class Traceback(list): """ cache = {} for i, entry in enumerate(self): - key = entry.frame.code.path, entry.lineno + key = entry.frame.code.path, entry.lineno #print "checking for recursion at", key l = cache.setdefault(key, []) - if l: + if l: f = entry.frame loc = f.f_locals - for otherloc in l: - if f.is_true(f.eval(co_equal, + for otherloc in l: + if f.is_true(f.eval(co_equal, __recursioncache_locals_1=loc, __recursioncache_locals_2=otherloc)): - return i + return i l.append(entry.frame.f_locals) return None @@ -303,7 +303,7 @@ class ExceptionInfo(object): """ wraps sys.exc_info() objects and offers help for navigating the traceback. """ - _striptext = '' + _striptext = '' def __init__(self, tup=None, exprinfo=None): # NB. all attributes are private! Subclasses or other # ExceptionInfo-like classes may have different attributes. @@ -318,14 +318,14 @@ class ExceptionInfo(object): self._excinfo = tup self.type, self.value, tb = self._excinfo self.typename = self.type.__name__ - self.traceback = py.code.Traceback(tb) + self.traceback = py.code.Traceback(tb) def __repr__(self): return "" % (self.typename, len(self.traceback)) - def exconly(self, tryshort=False): + def exconly(self, tryshort=False): """ return the exception as a string - + when 'tryshort' resolves to True, and the exception is a py.code._AssertionError, only the actual exception part of the exception representation is returned (so 'AssertionError: ' is @@ -334,14 +334,14 @@ class ExceptionInfo(object): lines = py.std.traceback.format_exception_only(self.type, self.value) text = ''.join(lines) text = text.rstrip() - if tryshort: - if text.startswith(self._striptext): + if tryshort: + if text.startswith(self._striptext): text = text[len(self._striptext):] return text - def errisinstance(self, exc): + def errisinstance(self, exc): """ return True if the exception is an instance of exc """ - return isinstance(self.value, exc) + return isinstance(self.value, exc) def _getreprcrash(self): exconly = self.exconly(tryshort=True) @@ -350,14 +350,14 @@ class ExceptionInfo(object): reprcrash = ReprFileLocation(path, lineno+1, exconly) return reprcrash - def getrepr(self, showlocals=False, style="long", + def getrepr(self, showlocals=False, style="long", abspath=False, tbfilter=True, funcargs=False): """ return str()able representation of this exception info. - showlocals: show locals per traceback entry - style: long|short|no traceback style + showlocals: show locals per traceback entry + style: long|short|no traceback style tbfilter: hide entries (where __tracebackhide__ is true) """ - fmt = FormattedExcinfo(showlocals=showlocals, style=style, + fmt = FormattedExcinfo(showlocals=showlocals, style=style, abspath=abspath, tbfilter=tbfilter, funcargs=funcargs) return fmt.repr_excinfo(self) @@ -370,27 +370,27 @@ class ExceptionInfo(object): entry = self.traceback[-1] loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly()) return unicode(loc) - + class FormattedExcinfo(object): - """ presenting information about failing Functions and Generators. """ - # for traceback entries - flow_marker = ">" + """ presenting information about failing Functions and Generators. """ + # for traceback entries + flow_marker = ">" fail_marker = "E" - + def __init__(self, showlocals=False, style="long", abspath=True, tbfilter=True, funcargs=False): self.showlocals = showlocals self.style = style self.tbfilter = tbfilter self.funcargs = funcargs - self.abspath = abspath + self.abspath = abspath def _getindent(self, source): - # figure out indent for given source + # figure out indent for given source try: s = str(source.getstatement(len(source)-1)) - except KeyboardInterrupt: - raise + except KeyboardInterrupt: + raise except: try: s = str(source[-1]) @@ -405,7 +405,7 @@ class FormattedExcinfo(object): if source is not None: source = source.deindent() return source - + def _saferepr(self, obj): return py.io.saferepr(obj) @@ -421,7 +421,7 @@ class FormattedExcinfo(object): lines = [] if source is None: source = py.code.Source("???") - line_index = 0 + line_index = 0 if line_index < 0: line_index += len(source) for i in range(len(source)): @@ -440,24 +440,24 @@ class FormattedExcinfo(object): def get_exconly(self, excinfo, indent=4, markall=False): lines = [] - indent = " " * indent - # get the real exception information out + indent = " " * indent + # get the real exception information out exlines = excinfo.exconly(tryshort=True).split('\n') failindent = self.fail_marker + indent[1:] for line in exlines: lines.append(failindent + line) if not markall: - failindent = indent + failindent = indent return lines def repr_locals(self, locals): - if self.showlocals: + if self.showlocals: lines = [] keys = list(locals) keys.sort() for name in keys: value = locals[name] - if name == '__builtins__': + if name == '__builtins__': lines.append("__builtins__ = ") else: # This formatting could all be handled by the @@ -474,7 +474,7 @@ class FormattedExcinfo(object): return ReprLocals(lines) def repr_traceback_entry(self, entry, excinfo=None): - # excinfo is not None if this is the last tb entry + # excinfo is not None if this is the last tb entry source = self._getentrysource(entry) if source is None: source = py.code.Source("???") @@ -488,7 +488,7 @@ class FormattedExcinfo(object): short = self.style == "short" reprargs = None if not short: - reprargs = self.repr_args(entry) + reprargs = self.repr_args(entry) s = self.get_source(source, line_index, excinfo, short=short) lines.extend(s) if short: @@ -501,7 +501,7 @@ class FormattedExcinfo(object): if not short: localsrepr = self.repr_locals(entry.locals) return ReprEntry(lines, reprargs, localsrepr, filelocrepr, short) - if excinfo: + if excinfo: lines.extend(self.get_exconly(excinfo, indent=4)) return ReprEntry(lines, None, None, None, False) @@ -512,8 +512,8 @@ class FormattedExcinfo(object): path = np return path - def repr_traceback(self, excinfo): - traceback = excinfo.traceback + def repr_traceback(self, excinfo): + traceback = excinfo.traceback if self.tbfilter: traceback = traceback.filter() recursionindex = None @@ -522,7 +522,7 @@ class FormattedExcinfo(object): last = traceback[-1] entries = [] extraline = None - for index, entry in enumerate(traceback): + for index, entry in enumerate(traceback): einfo = (last == entry) and excinfo or None reprentry = self.repr_traceback_entry(entry, einfo) entries.append(reprentry) @@ -564,7 +564,7 @@ def unicode_or_repr(obj): class ReprExceptionInfo(TerminalRepr): def __init__(self, reprtraceback, reprcrash): self.reprtraceback = reprtraceback - self.reprcrash = reprcrash + self.reprcrash = reprcrash self.sections = [] def addsection(self, name, content, sep="-"): @@ -575,7 +575,7 @@ class ReprExceptionInfo(TerminalRepr): for name, content, sep in self.sections: tw.sep(sep, name) tw.line(content) - + class ReprTraceback(TerminalRepr): entrysep = "_ " @@ -585,7 +585,7 @@ class ReprTraceback(TerminalRepr): self.style = style def toterminal(self, tw): - sepok = False + sepok = False for entry in self.reprentries: if self.style == "long": if sepok: @@ -602,7 +602,7 @@ class ReprEntry(TerminalRepr): def __init__(self, lines, reprfuncargs, reprlocals, filelocrepr, short): self.lines = lines self.reprfuncargs = reprfuncargs - self.reprlocals = reprlocals + self.reprlocals = reprlocals self.reprfileloc = filelocrepr self.short = short @@ -610,14 +610,14 @@ class ReprEntry(TerminalRepr): if self.short: self.reprfileloc.toterminal(tw) for line in self.lines: - red = line.startswith("E ") + red = line.startswith("E ") tw.line(line, bold=True, red=red) #tw.line("") return if self.reprfuncargs: self.reprfuncargs.toterminal(tw) for line in self.lines: - red = line.startswith("E ") + red = line.startswith("E ") tw.line(line, bold=True, red=red) if self.reprlocals: #tw.sep(self.localssep, "Locals") @@ -628,8 +628,8 @@ class ReprEntry(TerminalRepr): self.reprfileloc.toterminal(tw) def __str__(self): - return "%s\n%s\n%s" % ("\n".join(self.lines), - self.reprlocals, + return "%s\n%s\n%s" % ("\n".join(self.lines), + self.reprlocals, self.reprfileloc) class ReprFileLocation(TerminalRepr): @@ -641,15 +641,15 @@ class ReprFileLocation(TerminalRepr): def toterminal(self, tw): # filename and lineno output for each entry, # using an output format that most editors unterstand - msg = self.message + msg = self.message i = msg.find("\n") if i != -1: - msg = msg[:i] + msg = msg[:i] tw.line("%s:%s: %s" %(self.path, self.lineno, msg)) class ReprLocals(TerminalRepr): def __init__(self, lines): - self.lines = lines + self.lines = lines def toterminal(self, tw): for line in self.lines: @@ -667,7 +667,7 @@ class ReprFuncArgs(TerminalRepr): if len(ns) + len(linesofar) + 2 > tw.fullwidth: if linesofar: tw.line(linesofar) - linesofar = ns + linesofar = ns else: if linesofar: linesofar += ", " + ns @@ -688,7 +688,7 @@ def patch_builtins(assertion=True, compile=True): l = oldbuiltins.setdefault('AssertionError', []) l.append(py.builtin.builtins.AssertionError) py.builtin.builtins.AssertionError = assertion.AssertionError - if compile: + if compile: l = oldbuiltins.setdefault('compile', []) l.append(py.builtin.builtins.compile) py.builtin.builtins.compile = py.code.compile @@ -697,14 +697,14 @@ def unpatch_builtins(assertion=True, compile=True): """ remove compile and AssertionError builtins from Python builtins. """ if assertion: py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() - if compile: + if compile: py.builtin.builtins.compile = oldbuiltins['compile'].pop() def getrawcode(obj): - """ return code object for given function. """ + """ return code object for given function. """ obj = getattr(obj, 'im_func', obj) obj = getattr(obj, 'func_code', obj) obj = getattr(obj, 'f_code', obj) obj = getattr(obj, '__code__', obj) return obj - + diff --git a/py/_code/oldmagic.py b/py/_code/oldmagic.py index 51db7f572..7b52c4fca 100644 --- a/py/_code/oldmagic.py +++ b/py/_code/oldmagic.py @@ -1,6 +1,6 @@ -""" deprecated module for turning on/off some features. """ +""" deprecated module for turning on/off some features. """ -import py +import py from py.builtin import builtins as cpy_builtin @@ -12,17 +12,17 @@ def invoke(assertion=False, compile=False): of deploying a mini-interpreter constructs a useful error message. """ - py.log._apiwarn("1.1", + py.log._apiwarn("1.1", "py.magic.invoke() is deprecated, use py.code.patch_builtins()", - stacklevel=2, + stacklevel=2, ) py.code.patch_builtins(assertion=assertion, compile=compile) def revoke(assertion=False, compile=False): """ (deprecated) revoke previously invoked magic (see invoke()).""" - py.log._apiwarn("1.1", + py.log._apiwarn("1.1", "py.magic.revoke() is deprecated, use py.code.unpatch_builtins()", - stacklevel=2, + stacklevel=2, ) py.code.unpatch_builtins(assertion=assertion, compile=compile) @@ -34,9 +34,9 @@ def patch(namespace, name, value): invocations to the same namespace/name pair will remember a list of old values. """ - py.log._apiwarn("1.1", - "py.magic.patch() is deprecated, in tests use monkeypatch funcarg.", - stacklevel=2, + py.log._apiwarn("1.1", + "py.magic.patch() is deprecated, in tests use monkeypatch funcarg.", + stacklevel=2, ) nref = (namespace, name) orig = getattr(namespace, name) @@ -48,9 +48,9 @@ def revert(namespace, name): """ (deprecated) revert to the orginal value the last patch modified. Raise ValueError if no such original value exists. """ - py.log._apiwarn("1.1", + py.log._apiwarn("1.1", "py.magic.revert() is deprecated, in tests use monkeypatch funcarg.", - stacklevel=2, + stacklevel=2, ) nref = (namespace, name) if nref not in patched or not patched[nref]: diff --git a/py/_code/source.py b/py/_code/source.py index 87e61d4d1..0f47d3d8d 100644 --- a/py/_code/source.py +++ b/py/_code/source.py @@ -3,7 +3,7 @@ import sys import inspect, tokenize import py from types import ModuleType -cpy_compile = compile +cpy_compile = compile try: import _ast @@ -21,9 +21,9 @@ class Source(object): def __init__(self, *parts, **kwargs): self.lines = lines = [] de = kwargs.get('deindent', True) - rstrip = kwargs.get('rstrip', True) + rstrip = kwargs.get('rstrip', True) for part in parts: - if not part: + if not part: partlines = [] if isinstance(part, Source): partlines = part.lines @@ -32,8 +32,8 @@ class Source(object): elif isinstance(part, py.builtin._basestring): partlines = part.split('\n') if rstrip: - while partlines: - if partlines[-1].strip(): + while partlines: + if partlines[-1].strip(): break partlines.pop() else: @@ -42,13 +42,13 @@ class Source(object): partlines = deindent(partlines) lines.extend(partlines) - def __eq__(self, other): + def __eq__(self, other): try: - return self.lines == other.lines - except AttributeError: - if isinstance(other, str): - return str(self) == other - return False + return self.lines == other.lines + except AttributeError: + if isinstance(other, str): + return str(self) == other + return False def __getitem__(self, key): if isinstance(key, int): @@ -58,8 +58,8 @@ class Source(object): raise IndexError("cannot slice a Source with a step") return self.__getslice__(key.start, key.stop) - def __len__(self): - return len(self.lines) + def __len__(self): + return len(self.lines) def __getslice__(self, start, end): newsource = Source() @@ -79,9 +79,9 @@ class Source(object): source.lines[:] = self.lines[start:end] return source - def putaround(self, before='', after='', indent=' ' * 4): - """ return a copy of the source object with - 'before' and 'after' wrapped around it. + def putaround(self, before='', after='', indent=' ' * 4): + """ return a copy of the source object with + 'before' and 'after' wrapped around it. """ before = Source(before) after = Source(after) @@ -90,9 +90,9 @@ class Source(object): newsource.lines = before.lines + lines + after.lines return newsource - def indent(self, indent=' ' * 4): - """ return a copy of the source object with - all lines indented by the given indent-string. + def indent(self, indent=' ' * 4): + """ return a copy of the source object with + all lines indented by the given indent-string. """ newsource = Source() newsource.lines = [(indent+line) for line in self.lines] @@ -106,7 +106,7 @@ class Source(object): return self[start:end] def getstatementrange(self, lineno): - """ return (start, end) tuple which spans the minimal + """ return (start, end) tuple which spans the minimal statement region which containing the given lineno. """ # XXX there must be a better than these heuristic ways ... @@ -159,7 +159,7 @@ class Source(object): def isparseable(self, deindent=True): """ return True if source is parseable, heuristically - deindenting it by default. + deindenting it by default. """ try: import parser @@ -167,7 +167,7 @@ class Source(object): syntax_checker = lambda x: compile(x, 'asd', 'exec') else: syntax_checker = parser.suite - + if deindent: source = str(self.deindent()) else: @@ -185,14 +185,14 @@ class Source(object): def __str__(self): return "\n".join(self.lines) - def compile(self, filename=None, mode='exec', - flag=generators.compiler_flag, + def compile(self, filename=None, mode='exec', + flag=generators.compiler_flag, dont_inherit=0, _genframe=None): """ return compiled code object. if filename is None invent an artificial filename which displays the source/line position of the caller frame. """ - if not filename or py.path.local(filename).check(file=0): + if not filename or py.path.local(filename).check(file=0): if _genframe is None: _genframe = sys._getframe(1) # the caller fn,lineno = _genframe.f_code.co_filename, _genframe.f_lineno @@ -240,8 +240,8 @@ def compile_(source, filename=None, mode='exec', flags= generators.compiler_flag, dont_inherit=0): """ compile the given source to a raw code object, and maintain an internal cache which allows later - retrieval of the source code for the code object - and any recursively created code objects. + retrieval of the source code for the code object + and any recursively created code objects. """ if _ast is not None and isinstance(source, _ast.AST): # XXX should Source support having AST? @@ -256,7 +256,7 @@ def getfslineno(obj): try: code = py.code.Code(obj) except TypeError: - # fallback to + # fallback to fn = (py.std.inspect.getsourcefile(obj) or py.std.inspect.getfile(obj)) fspath = fn and py.path.local(fn) or None @@ -269,7 +269,7 @@ def getfslineno(obj): lineno = None else: fspath = code.path - lineno = code.firstlineno + lineno = code.firstlineno return fspath, lineno # @@ -314,9 +314,9 @@ def deindent(lines, offset=None): yield line + '\n' while True: yield '' - + r = readline_generator(lines) - try: + try: readline = r.next except AttributeError: readline = r.__next__ diff --git a/py/_compat/dep_doctest.py b/py/_compat/dep_doctest.py index 6da68a500..84d9e16ef 100644 --- a/py/_compat/dep_doctest.py +++ b/py/_compat/dep_doctest.py @@ -1,5 +1,5 @@ import py -py.log._apiwarn("1.1", "py.compat.doctest deprecated, use standard library version.", +py.log._apiwarn("1.1", "py.compat.doctest deprecated, use standard library version.", stacklevel="apipkg") doctest = py.std.doctest diff --git a/py/_compat/dep_optparse.py b/py/_compat/dep_optparse.py index 253d40fe4..37d8478aa 100644 --- a/py/_compat/dep_optparse.py +++ b/py/_compat/dep_optparse.py @@ -1,4 +1,4 @@ import py py.log._apiwarn("1.1", "py.compat.optparse deprecated, use standard library version.", stacklevel="apipkg") -optparse = py.std.optparse +optparse = py.std.optparse diff --git a/py/_compat/dep_subprocess.py b/py/_compat/dep_subprocess.py index dac3d6916..5431c9f87 100644 --- a/py/_compat/dep_subprocess.py +++ b/py/_compat/dep_subprocess.py @@ -1,5 +1,5 @@ import py -py.log._apiwarn("1.1", "py.compat.subprocess deprecated, use standard library version.", +py.log._apiwarn("1.1", "py.compat.subprocess deprecated, use standard library version.", stacklevel="apipkg") subprocess = py.std.subprocess diff --git a/py/_compat/dep_textwrap.py b/py/_compat/dep_textwrap.py index 3f378298e..8750747dd 100644 --- a/py/_compat/dep_textwrap.py +++ b/py/_compat/dep_textwrap.py @@ -1,5 +1,5 @@ import py -py.log._apiwarn("1.1", "py.compat.textwrap deprecated, use standard library version.", +py.log._apiwarn("1.1", "py.compat.textwrap deprecated, use standard library version.", stacklevel="apipkg") textwrap = py.std.textwrap diff --git a/py/_error.py b/py/_error.py index bd183e0db..1062bbacf 100644 --- a/py/_error.py +++ b/py/_error.py @@ -1,5 +1,5 @@ """ -create errno-specific classes for IO or os calls. +create errno-specific classes for IO or os calls. """ import sys, os, errno @@ -20,8 +20,8 @@ class Error(EnvironmentError): return s _winerrnomap = { - 2: errno.ENOENT, - 3: errno.ENOENT, + 2: errno.ENOENT, + 3: errno.ENOENT, 17: errno.EEXIST, 22: errno.ENOTDIR, 267: errno.ENOTDIR, @@ -29,9 +29,9 @@ _winerrnomap = { } class ErrorMaker(object): - """ lazily provides Exception classes for each possible POSIX errno - (as defined per the 'errno' module). All such instances - subclass EnvironmentError. + """ lazily provides Exception classes for each possible POSIX errno + (as defined per the 'errno' module). All such instances + subclass EnvironmentError. """ Error = Error _errno2class = {} @@ -65,18 +65,18 @@ class ErrorMaker(object): if not hasattr(value, 'errno'): raise __tracebackhide__ = False - errno = value.errno + errno = value.errno try: - if not isinstance(value, WindowsError): + if not isinstance(value, WindowsError): raise NameError - except NameError: + except NameError: # we are not on Windows, or we got a proper OSError cls = self._geterrnoclass(errno) - else: - try: - cls = self._geterrnoclass(_winerrnomap[errno]) - except KeyError: - raise value + else: + try: + cls = self._geterrnoclass(_winerrnomap[errno]) + except KeyError: + raise value raise cls("%s%r" % (func.__name__, args)) __tracebackhide__ = True diff --git a/py/_io/capture.py b/py/_io/capture.py index b2decd60f..d0dafea86 100644 --- a/py/_io/capture.py +++ b/py/_io/capture.py @@ -3,9 +3,9 @@ import sys import py import tempfile -try: +try: from io import StringIO -except ImportError: +except ImportError: from StringIO import StringIO if sys.version_info < (3,0): @@ -28,21 +28,21 @@ except ImportError: patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} -class FDCapture: +class FDCapture: """ Capture IO to/from a given os-level filedescriptor. """ - + def __init__(self, targetfd, tmpfile=None, now=True, patchsys=False): - """ save targetfd descriptor, and open a new - temporary file there. If no tmpfile is + """ save targetfd descriptor, and open a new + temporary file there. If no tmpfile is specified a tempfile.Tempfile() will be opened - in text mode. + in text mode. """ self.targetfd = targetfd if tmpfile is None and targetfd != 0: f = tempfile.TemporaryFile('wb+') - tmpfile = dupfile(f, encoding="UTF-8") + tmpfile = dupfile(f, encoding="UTF-8") f.close() - self.tmpfile = tmpfile + self.tmpfile = tmpfile self._savefd = os.dup(self.targetfd) if patchsys: self._oldsys = getattr(sys, patchsysdict[targetfd]) @@ -63,20 +63,20 @@ class FDCapture: setattr(sys, patchsysdict[self.targetfd], DontReadFromInput()) else: fd = self.tmpfile.fileno() - os.dup2(self.tmpfile.fileno(), self.targetfd) + os.dup2(self.tmpfile.fileno(), self.targetfd) if hasattr(self, '_oldsys'): setattr(sys, patchsysdict[self.targetfd], self.tmpfile) - def done(self): + def done(self): """ unpatch and clean up, returns the self.tmpfile (file object) """ - os.dup2(self._savefd, self.targetfd) - os.close(self._savefd) + os.dup2(self._savefd, self.targetfd) + os.close(self._savefd) if self.targetfd != 0: self.tmpfile.seek(0) if hasattr(self, '_oldsys'): setattr(sys, patchsysdict[self.targetfd], self._oldsys) - return self.tmpfile + return self.tmpfile def writeorg(self, data): """ write a string to the original file descriptor @@ -89,22 +89,22 @@ class FDCapture: tempfp.close() -def dupfile(f, mode=None, buffering=0, raising=False, encoding=None): +def dupfile(f, mode=None, buffering=0, raising=False, encoding=None): """ return a new open file object that's a duplicate of f - mode is duplicated if not given, 'buffering' controls + mode is duplicated if not given, 'buffering' controls buffer size (defaulting to no buffering) and 'raising' defines whether an exception is raised when an incompatible file object is passed in (if raising is False, the file object itself will be returned) """ - try: - fd = f.fileno() - except AttributeError: - if raising: - raise + try: + fd = f.fileno() + except AttributeError: + if raising: + raise return f - newfd = os.dup(fd) + newfd = os.dup(fd) mode = mode and mode or f.mode if sys.version_info >= (3,0): if encoding is not None: @@ -112,7 +112,7 @@ def dupfile(f, mode=None, buffering=0, raising=False, encoding=None): buffering = True return os.fdopen(newfd, mode, buffering, encoding, closefd=True) else: - f = os.fdopen(newfd, mode, buffering) + f = os.fdopen(newfd, mode, buffering) if encoding is not None: return EncodedFile(f, encoding) return f @@ -139,24 +139,24 @@ class EncodedFile(object): return getattr(self._stream, name) class Capture(object): - def call(cls, func, *args, **kwargs): + def call(cls, func, *args, **kwargs): """ return a (res, out, err) tuple where out and err represent the output/error output - during function execution. + during function execution. call the given function with args/kwargs - and capture output/error during its execution. - """ + and capture output/error during its execution. + """ so = cls() - try: + try: res = func(*args, **kwargs) - finally: + finally: out, err = so.reset() - return res, out, err - call = classmethod(call) + return res, out, err + call = classmethod(call) def reset(self): """ reset sys.stdout/stderr and return captured output as strings. """ - outfile, errfile = self.done() + outfile, errfile = self.done() out, err = "", "" if outfile and not outfile.closed: out = outfile.read() @@ -173,13 +173,13 @@ class Capture(object): return outerr -class StdCaptureFD(Capture): - """ This class allows to capture writes to FD1 and FD2 +class StdCaptureFD(Capture): + """ This class allows to capture writes to FD1 and FD2 and may connect a NULL file to FD0 (and prevent - reads from sys.stdin). If any of the 0,1,2 file descriptors - is invalid it will not be captured. + reads from sys.stdin). If any of the 0,1,2 file descriptors + is invalid it will not be captured. """ - def __init__(self, out=True, err=True, mixed=False, + def __init__(self, out=True, err=True, mixed=False, in_=True, patchsys=True, now=True): self._options = locals() self._save() @@ -197,30 +197,30 @@ class StdCaptureFD(Capture): self.in_ = FDCapture(0, tmpfile=None, now=False, patchsys=patchsys) except OSError: - pass + pass if out: tmpfile = None if hasattr(out, 'write'): tmpfile = out try: - self.out = FDCapture(1, tmpfile=tmpfile, + self.out = FDCapture(1, tmpfile=tmpfile, now=False, patchsys=patchsys) self._options['out'] = self.out.tmpfile except OSError: - pass + pass if err: if out and mixed: - tmpfile = self.out.tmpfile + tmpfile = self.out.tmpfile elif hasattr(err, 'write'): tmpfile = err else: tmpfile = None try: - self.err = FDCapture(2, tmpfile=tmpfile, - now=False, patchsys=patchsys) + self.err = FDCapture(2, tmpfile=tmpfile, + now=False, patchsys=patchsys) self._options['err'] = self.err.tmpfile except OSError: - pass + pass def startall(self): if hasattr(self, 'in_'): @@ -238,13 +238,13 @@ class StdCaptureFD(Capture): """ return (outfile, errfile) and stop capturing. """ outfile = errfile = None if hasattr(self, 'out') and not self.out.tmpfile.closed: - outfile = self.out.done() + outfile = self.out.done() if hasattr(self, 'err') and not self.err.tmpfile.closed: - errfile = self.err.done() + errfile = self.err.done() if hasattr(self, 'in_'): tmpfile = self.in_.done() self._save() - return outfile, errfile + return outfile, errfile def readouterr(self): """ return snapshot value of stdout/stderr capturings. """ @@ -258,13 +258,13 @@ class StdCaptureFD(Capture): f.truncate(0) f.seek(0) l.append(res) - return l + return l class StdCapture(Capture): """ This class allows to capture writes to sys.stdout|stderr "in-memory" and will raise errors on tries to read from sys.stdin. It only - modifies sys.stdout|stderr|stdin attributes and does not - touch underlying File Descriptors (use StdCaptureFD for that). + modifies sys.stdout|stderr|stdin attributes and does not + touch underlying File Descriptors (use StdCaptureFD for that). """ def __init__(self, out=True, err=True, in_=True, mixed=False, now=True): self._oldout = sys.stdout @@ -284,26 +284,26 @@ class StdCapture(Capture): self.startall() def startall(self): - if self.out: + if self.out: sys.stdout = self.out - if self.err: + if self.err: sys.stderr = self.err if self.in_: sys.stdin = self.in_ = DontReadFromInput() - def done(self): + def done(self): """ return (outfile, errfile) and stop capturing. """ outfile = errfile = None if self.out and not self.out.closed: - sys.stdout = self._oldout + sys.stdout = self._oldout outfile = self.out outfile.seek(0) - if self.err and not self.err.closed: - sys.stderr = self._olderr - errfile = self.err + if self.err and not self.err.closed: + sys.stderr = self._olderr + errfile = self.err errfile.seek(0) if self.in_: - sys.stdin = self._oldin + sys.stdin = self._oldin return outfile, errfile def resume(self): @@ -321,7 +321,7 @@ class StdCapture(Capture): err = self.err.getvalue() self.err.truncate(0) self.err.seek(0) - return out, err + return out, err class DontReadFromInput: """Temporary stub class. Ideally when stdin is accessed, the @@ -335,9 +335,9 @@ class DontReadFromInput: readline = read readlines = read __iter__ = read - + def fileno(self): - raise ValueError("redirected Stdin is pseudofile, has no fileno()") + raise ValueError("redirected Stdin is pseudofile, has no fileno()") def isatty(self): return False def close(self): diff --git a/py/_io/saferepr.py b/py/_io/saferepr.py index 215bfc286..db52ca92b 100644 --- a/py/_io/saferepr.py +++ b/py/_io/saferepr.py @@ -8,15 +8,15 @@ reprlib = py.builtin._tryimport('repr', 'reprlib') sysex = (KeyboardInterrupt, MemoryError, SystemExit) class SafeRepr(reprlib.Repr): - """ subclass of repr.Repr that limits the resulting size of repr() - and includes information on exceptions raised during the call. - """ + """ subclass of repr.Repr that limits the resulting size of repr() + and includes information on exceptions raised during the call. + """ def repr(self, x): return self._callhelper(reprlib.Repr.repr, self, x) def repr_instance(self, x, level): return self._callhelper(builtin_repr, x) - + def _callhelper(self, call, x, *args): try: # Try the vanilla repr and make sure that the result is a string @@ -42,11 +42,11 @@ class SafeRepr(reprlib.Repr): return s def saferepr(obj, maxsize=240): - """ return a size-limited safe repr-string for the given object. + """ return a size-limited safe repr-string for the given object. Failing __repr__ functions of user instances will be represented with a short exception info and 'saferepr' generally takes care to never raise exceptions itself. This function is a wrapper - around the Repr/reprlib functionality of the standard 2.6 lib. + around the Repr/reprlib functionality of the standard 2.6 lib. """ # review exception handling srepr = SafeRepr() diff --git a/py/_io/terminalwriter.py b/py/_io/terminalwriter.py index 4feb3d66d..e0bef77c4 100644 --- a/py/_io/terminalwriter.py +++ b/py/_io/terminalwriter.py @@ -1,6 +1,6 @@ """ -Helper functions for writing to terminals and files. +Helper functions for writing to terminals and files. """ @@ -20,7 +20,7 @@ def _getdimensions(): import termios,fcntl,struct call = fcntl.ioctl(1,termios.TIOCGWINSZ,"\000"*8) height,width = struct.unpack( "hhhh", call ) [:2] - return height, width + return height, width def get_terminal_width(): @@ -32,7 +32,7 @@ def get_terminal_width(): # FALLBACK width = int(os.environ.get('COLUMNS', 80)) else: - # XXX the windows getdimensions may be bogus, let's sanify a bit + # XXX the windows getdimensions may be bogus, let's sanify a bit if width < 40: width = 80 return width @@ -47,7 +47,7 @@ def ansi_print(text, esc, file=None, newline=True, flush=False): if esc and not isinstance(esc, tuple): esc = (esc,) if esc and sys.platform != "win32" and file.isatty(): - text = (''.join(['\x1b[%sm' % cod for cod in esc]) + + text = (''.join(['\x1b[%sm' % cod for cod in esc]) + text + '\x1b[0m') # ANSI color code "reset" if newline: @@ -93,9 +93,9 @@ def should_do_markup(file): and not (sys.platform.startswith('java') and os._name == 'nt') class TerminalWriter(object): - _esctable = dict(black=30, red=31, green=32, yellow=33, + _esctable = dict(black=30, red=31, green=32, yellow=33, blue=34, purple=35, cyan=36, white=37, - Black=40, Red=41, Green=42, Yellow=43, + Black=40, Red=41, Green=42, Yellow=43, Blue=44, Purple=45, Cyan=46, White=47, bold=1, light=2, blink=5, invert=7) @@ -106,19 +106,19 @@ class TerminalWriter(object): if stringio: self.stringio = file = py.io.TextIO() else: - file = py.std.sys.stdout + file = py.std.sys.stdout if hasattr(file, 'encoding'): encoding = file.encoding elif hasattr(file, '__call__'): file = WriteFile(file, encoding=encoding) - self.encoding = encoding + self.encoding = encoding self._file = file self.fullwidth = get_terminal_width() self.hasmarkup = should_do_markup(file) def _escaped(self, text, esc): if esc and self.hasmarkup: - text = (''.join(['\x1b[%sm' % cod for cod in esc]) + + text = (''.join(['\x1b[%sm' % cod for cod in esc]) + text +'\x1b[0m') return text @@ -210,18 +210,18 @@ class Win32ConsoleWriter(TerminalWriter): def line(self, s="", **kw): self.write(s+"\n", **kw) -class WriteFile(object): - def __init__(self, writemethod, encoding=None): - self.encoding = encoding - self._writemethod = writemethod +class WriteFile(object): + def __init__(self, writemethod, encoding=None): + self.encoding = encoding + self._writemethod = writemethod def write(self, data): if self.encoding: data = data.encode(self.encoding) self._writemethod(data) - def flush(self): - return + def flush(self): + return if win32_and_ctypes: diff --git a/py/_log/log.py b/py/_log/log.py index a32e850c5..ce47e8c75 100644 --- a/py/_log/log.py +++ b/py/_log/log.py @@ -1,34 +1,34 @@ """ -basic logging functionality based on a producer/consumer scheme. +basic logging functionality based on a producer/consumer scheme. XXX implement this API: (maybe put it into slogger.py?) log = Logger( - info=py.log.STDOUT, - debug=py.log.STDOUT, + info=py.log.STDOUT, + debug=py.log.STDOUT, command=None) log.info("hello", "world") log.command("hello", "world") - log = Logger(info=Logger(something=...), - debug=py.log.STDOUT, + log = Logger(info=Logger(something=...), + debug=py.log.STDOUT, command=None) """ import py, sys -class Message(object): - def __init__(self, keywords, args): - self.keywords = keywords - self.args = args +class Message(object): + def __init__(self, keywords, args): + self.keywords = keywords + self.args = args - def content(self): + def content(self): return " ".join(map(str, self.args)) - def prefix(self): + def prefix(self): return "[%s] " % (":".join(self.keywords)) - def __str__(self): - return self.prefix() + self.content() + def __str__(self): + return self.prefix() + self.content() class Producer(object): @@ -36,11 +36,11 @@ class Producer(object): to a 'consumer' object, which then prints them to stdout, stderr, files, etc. Used extensively by PyPy-1.1. """ - - Message = Message # to allow later customization + + Message = Message # to allow later customization keywords2consumer = {} - def __init__(self, keywords, keywordmapper=None, **kw): + def __init__(self, keywords, keywordmapper=None, **kw): if hasattr(keywords, 'split'): keywords = tuple(keywords.split()) self._keywords = keywords @@ -49,22 +49,22 @@ class Producer(object): self._keywordmapper = keywordmapper def __repr__(self): - return "" % ":".join(self._keywords) + return "" % ":".join(self._keywords) def __getattr__(self, name): - if '_' in name: + if '_' in name: raise AttributeError(name) producer = self.__class__(self._keywords + (name,)) setattr(self, name, producer) - return producer - + return producer + def __call__(self, *args): """ write a message to the appropriate consumer(s) """ func = self._keywordmapper.getconsumer(self._keywords) - if func is not None: + if func is not None: func(self.Message(self._keywords, args)) -class KeywordMapper: +class KeywordMapper: def __init__(self): self.keywords2consumer = {} @@ -75,36 +75,36 @@ class KeywordMapper: self.keywords2consumer.update(state) def getconsumer(self, keywords): - """ return a consumer matching the given keywords. - + """ return a consumer matching the given keywords. + tries to find the most suitable consumer by walking, starting from the back, the list of keywords, the first consumer matching a keyword is returned (falling back to py.log.default) """ - for i in range(len(keywords), 0, -1): - try: + for i in range(len(keywords), 0, -1): + try: return self.keywords2consumer[keywords[:i]] - except KeyError: + except KeyError: continue return self.keywords2consumer.get('default', default_consumer) - def setconsumer(self, keywords, consumer): - """ set a consumer for a set of keywords. """ - # normalize to tuples - if isinstance(keywords, str): + def setconsumer(self, keywords, consumer): + """ set a consumer for a set of keywords. """ + # normalize to tuples + if isinstance(keywords, str): keywords = tuple(filter(None, keywords.split())) - elif hasattr(keywords, '_keywords'): - keywords = keywords._keywords - elif not isinstance(keywords, tuple): + elif hasattr(keywords, '_keywords'): + keywords = keywords._keywords + elif not isinstance(keywords, tuple): raise TypeError("key %r is not a string or tuple" % (keywords,)) - if consumer is not None and not py.builtin.callable(consumer): - if not hasattr(consumer, 'write'): + if consumer is not None and not py.builtin.callable(consumer): + if not hasattr(consumer, 'write'): raise TypeError( "%r should be None, callable or file-like" % (consumer,)) consumer = File(consumer) - self.keywords2consumer[keywords] = consumer + self.keywords2consumer[keywords] = consumer -def default_consumer(msg): +def default_consumer(msg): """ the default consumer, prints the message to stdout (using 'print') """ sys.stderr.write(str(msg)+"\n") @@ -122,22 +122,22 @@ def getstate(): # Consumers # -class File(object): +class File(object): """ log consumer wrapping a file(-like) object """ - def __init__(self, f): + def __init__(self, f): assert hasattr(f, 'write') - #assert isinstance(f, file) or not hasattr(f, 'open') - self._file = f + #assert isinstance(f, file) or not hasattr(f, 'open') + self._file = f - def __call__(self, msg): + def __call__(self, msg): """ write a message to the log """ self._file.write(str(msg) + "\n") if hasattr(self._file, 'flush'): self._file.flush() -class Path(object): +class Path(object): """ log consumer that opens and writes to a Path """ - def __init__(self, filename, append=False, + def __init__(self, filename, append=False, delayed_create=False, buffering=False): self._append = append self._filename = str(filename) @@ -158,11 +158,11 @@ class Path(object): if not self._buffering: self._file.flush() -def STDOUT(msg): +def STDOUT(msg): """ consumer that writes to sys.stdout """ sys.stdout.write(str(msg)+"\n") -def STDERR(msg): +def STDERR(msg): """ consumer that writes to sys.stderr """ sys.stderr.write(str(msg)+"\n") diff --git a/py/_log/warning.py b/py/_log/warning.py index 9f46feeaf..722e31e91 100644 --- a/py/_log/warning.py +++ b/py/_log/warning.py @@ -4,11 +4,11 @@ class DeprecationWarning(DeprecationWarning): def __init__(self, msg, path, lineno): self.msg = msg self.path = path - self.lineno = lineno + self.lineno = lineno def __repr__(self): return "%s:%d: %s" %(self.path, self.lineno+1, self.msg) def __str__(self): - return self.msg + return self.msg def _apiwarn(startversion, msg, stacklevel=2, function=None): # below is mostly COPIED from python2.4/warnings.py's def warn() @@ -21,7 +21,7 @@ def _apiwarn(startversion, msg, stacklevel=2, function=None): co = frame.f_code if co.co_filename.find(stacklevel) == -1: if found: - stacklevel = level + stacklevel = level break else: found = True @@ -67,8 +67,8 @@ def warn(msg, stacklevel=1, function=None): filename = module path = py.path.local(filename) warning = DeprecationWarning(msg, path, lineno) - py.std.warnings.warn_explicit(warning, category=Warning, - filename=str(warning.path), + py.std.warnings.warn_explicit(warning, category=Warning, + filename=str(warning.path), lineno=warning.lineno, registry=py.std.warnings.__dict__.setdefault( "__warningsregistry__", {}) diff --git a/py/_path/cacheutil.py b/py/_path/cacheutil.py index bac07a981..992250475 100644 --- a/py/_path/cacheutil.py +++ b/py/_path/cacheutil.py @@ -1,12 +1,12 @@ """ This module contains multithread-safe cache implementations. -All Caches have +All Caches have - getorbuild(key, builder) - delentry(key) + getorbuild(key, builder) + delentry(key) -methods and allow configuration when instantiating the cache class. +methods and allow configuration when instantiating the cache class. """ from time import time as gettime @@ -24,7 +24,7 @@ class BasicCache(object): def _putentry(self, key, entry): self._prunelowestweight() - self._dict[key] = entry + self._dict[key] = entry def delentry(self, key, raising=False): try: @@ -46,14 +46,14 @@ class BasicCache(object): numentries = len(self._dict) if numentries >= self.maxentries: # evict according to entry's weight - items = [(entry.weight, key) + items = [(entry.weight, key) for key, entry in self._dict.items()] items.sort() index = numentries - self.prunenum if index > 0: for weight, key in items[:index]: # in MT situations the element might be gone - self.delentry(key, raising=False) + self.delentry(key, raising=False) class BuildcostAccessCache(BasicCache): """ A BuildTime/Access-counting cache implementation. @@ -78,7 +78,7 @@ class BuildcostAccessCache(BasicCache): class WeightedCountingEntry(object): def __init__(self, value, oneweight): self._value = value - self.weight = self._oneweight = oneweight + self.weight = self._oneweight = oneweight def value(self): self.weight += self._oneweight @@ -95,8 +95,8 @@ class AgingCache(BasicCache): def _getentry(self, key): entry = self._dict[key] if entry.isexpired(): - self.delentry(key) - raise KeyError(key) + self.delentry(key) + raise KeyError(key) return entry def _build(self, key, builder): @@ -111,4 +111,4 @@ class AgingEntry(object): def isexpired(self): t = gettime() - return t >= self.weight + return t >= self.weight diff --git a/py/_path/common.py b/py/_path/common.py index b8b620f02..3837b36e2 100644 --- a/py/_path/common.py +++ b/py/_path/common.py @@ -75,7 +75,7 @@ class Checkers: return False return True -class NeverRaised(Exception): +class NeverRaised(Exception): pass class PathBase(object): @@ -143,7 +143,7 @@ newline will be removed from the end of each line. """ def move(self, target): """ move this path to target. """ if target.relto(self): - raise py.error.EINVAL(target, + raise py.error.EINVAL(target, "cannot move path into a subdirectory of itself") try: self.rename(target) @@ -174,9 +174,9 @@ newline will be removed from the end of each line. """ def relto(self, relpath): """ return a string which is the relative part of the path - to the given 'relpath'. + to the given 'relpath'. """ - if not isinstance(relpath, (str, PathBase)): + if not isinstance(relpath, (str, PathBase)): raise TypeError("%r: not a string or path object" %(relpath,)) strrelpath = str(relpath) if strrelpath and strrelpath[-1] != self.sep: @@ -187,17 +187,17 @@ newline will be removed from the end of each line. """ if sys.platform == "win32" or getattr(os, '_name', None) == 'nt': if os.path.normcase(strself).startswith( os.path.normcase(strrelpath)): - return strself[len(strrelpath):] + return strself[len(strrelpath):] elif strself.startswith(strrelpath): return strself[len(strrelpath):] return "" - def bestrelpath(self, dest): - """ return a string which is a relative path from self - (assumed to be a directory) to dest such that - self.join(bestrelpath) == dest and if not such - path can be determined return dest. - """ + def bestrelpath(self, dest): + """ return a string which is a relative path from self + (assumed to be a directory) to dest such that + self.join(bestrelpath) == dest and if not such + path can be determined return dest. + """ try: if self == dest: return os.curdir @@ -212,9 +212,9 @@ newline will be removed from the end of each line. """ n = 0 l = [os.pardir] * n if reldest: - l.append(reldest) + l.append(reldest) target = dest.sep.join(l) - return target + return target except AttributeError: return str(dest) @@ -259,7 +259,7 @@ newline will be removed from the end of each line. """ def __lt__(self, other): try: - return self.strpath < other.strpath + return self.strpath < other.strpath except AttributeError: return str(self) < str(other) @@ -278,7 +278,7 @@ newline will be removed from the end of each line. """ """ if isinstance(fil, str): fil = FNMatcher(fil) - if rec: + if rec: if isinstance(rec, str): rec = fnmatch(fil) elif not hasattr(rec, '__call__'): @@ -287,7 +287,7 @@ newline will be removed from the end of each line. """ entries = self.listdir() except ignore: return - dirs = [p for p in entries + dirs = [p for p in entries if p.check(dir=1) and (rec is None or rec(p))] for subdir in dirs: for p in subdir.visit(fil=fil, rec=rec, ignore=ignore): diff --git a/py/_path/local.py b/py/_path/local.py index 156a88934..0e051eb8d 100644 --- a/py/_path/local.py +++ b/py/_path/local.py @@ -11,17 +11,17 @@ class Stat(object): def __getattr__(self, name): return getattr(self._osstatresult, "st_" + name) - def __init__(self, path, osstatresult): - self.path = path + def __init__(self, path, osstatresult): + self.path = path self._osstatresult = osstatresult def owner(self): if iswin32: raise NotImplementedError("XXX win32") - import pwd + import pwd entry = py.error.checked_call(pwd.getpwuid, self.uid) return entry[0] - owner = property(owner, None, None, "owner of path") + owner = property(owner, None, None, "owner of path") def group(self): """ return group name of file. """ @@ -30,7 +30,7 @@ class Stat(object): import grp entry = py.error.checked_call(grp.getgrgid, self.gid) return entry[0] - group = property(group) + group = property(group) class PosixPath(common.PathBase): def chown(self, user, group, rec=0): @@ -42,7 +42,7 @@ class PosixPath(common.PathBase): uid = getuserid(user) gid = getgroupid(group) if rec: - for x in self.visit(rec=lambda x: x.check(link=0)): + for x in self.visit(rec=lambda x: x.check(link=0)): if x.check(link=0): py.error.checked_call(os.chown, str(x), uid, gid) py.error.checked_call(os.chown, str(self), uid, gid) @@ -87,12 +87,12 @@ def getgroupid(group): FSBase = not iswin32 and PosixPath or common.PathBase class LocalPath(FSBase): - """ object oriented interface to os.path and other local filesystem - related information. + """ object oriented interface to os.path and other local filesystem + related information. """ class ImportMismatchError(ImportError): """ raised on pyimport() if there is a mismatch of __file__'s""" - + sep = os.sep class Checkers(common.Checkers): def _stat(self): @@ -149,7 +149,7 @@ class LocalPath(FSBase): def __eq__(self, other): s1 = str(self) s2 = str(other) - if iswin32: + if iswin32: s1 = s1.lower() s2 = s2.lower() return s1 == s2 @@ -161,21 +161,21 @@ class LocalPath(FSBase): return str(self) < str(other) def remove(self, rec=1, ignore_errors=False): - """ remove a file or directory (or a directory tree if rec=1). - if ignore_errors is True, errors while removing directories will + """ remove a file or directory (or a directory tree if rec=1). + if ignore_errors is True, errors while removing directories will be ignored. """ if self.check(dir=1, link=0): if rec: - # force remove of readonly files on windows - if iswin32: + # force remove of readonly files on windows + if iswin32: self.chmod(448, rec=1) # octcal 0700 py.error.checked_call(py.std.shutil.rmtree, self.strpath, ignore_errors=ignore_errors) else: py.error.checked_call(os.rmdir, self.strpath) else: - if iswin32: + if iswin32: self.chmod(448) # octcal 0700 py.error.checked_call(os.remove, self.strpath) @@ -197,7 +197,7 @@ class LocalPath(FSBase): buf = f.read(chunksize) if not buf: return hash.hexdigest() - hash.update(buf) + hash.update(buf) finally: f.close() @@ -235,7 +235,7 @@ class LocalPath(FSBase): obj.strpath = os.path.normpath( "%(drive)s%(dirname)s%(sep)s%(basename)s" % kw) return obj - + def _getbyspec(self, spec): """ return a sequence of specified path parts. 'spec' is a comma separated string containing path part names. @@ -321,7 +321,7 @@ class LocalPath(FSBase): if fil is None or fil(childurl): res.append(childurl) self._sortlist(res, sort) - return res + return res def size(self): """ return size of the underlying file object """ @@ -553,8 +553,8 @@ class LocalPath(FSBase): def sysexec(self, *argv, **popen_opts): """ return stdout text from executing a system child process, - where the 'self' path points to executable. - The process is directly invoked and not through a system shell. + where the 'self' path points to executable. + The process is directly invoked and not through a system shell. """ from subprocess import Popen, PIPE argv = map(str, argv) @@ -725,7 +725,7 @@ class LocalPath(FSBase): raise except: # this might be py.error.Error, WindowsError ... pass - + # make link... try: username = os.environ['USER'] #linux, et al @@ -770,7 +770,7 @@ def autopath(globs=None): the path will always point to a .py file or to None. the path will have the following payload: - pkgdir is the last parent directory path containing __init__.py + pkgdir is the last parent directory path containing __init__.py """ py.log._apiwarn("1.1", "py.magic.autopath deprecated, " "use py.path.local(__file__) and maybe pypkgpath/pyimport().") diff --git a/py/_path/svnurl.py b/py/_path/svnurl.py index 383b01ed4..f55b6c65d 100644 --- a/py/_path/svnurl.py +++ b/py/_path/svnurl.py @@ -1,7 +1,7 @@ """ module defining a subversion path object based on the external command 'svn'. This modules aims to work with svn 1.3 and higher -but might also interact well with earlier versions. +but might also interact well with earlier versions. """ import os, sys, time, re @@ -11,7 +11,7 @@ from py._path import common from py._path import svnwc as svncommon from py._path.cacheutil import BuildcostAccessCache, AgingCache -DEBUG=False +DEBUG=False class SvnCommandPath(svncommon.SvnPathBase): """ path implementation that offers access to (possibly remote) subversion @@ -22,10 +22,10 @@ class SvnCommandPath(svncommon.SvnPathBase): def __new__(cls, path, rev=None, auth=None): self = object.__new__(cls) - if isinstance(path, cls): - rev = path.rev + if isinstance(path, cls): + rev = path.rev auth = path.auth - path = path.strpath + path = path.strpath svncommon.checkbadchars(path) path = path.rstrip('/') self.strpath = path @@ -97,7 +97,7 @@ class SvnCommandPath(svncommon.SvnPathBase): def open(self, mode='r'): """ return an opened file with the given mode. """ - if mode not in ("r", "rU",): + if mode not in ("r", "rU",): raise ValueError("mode %r not supported" % (mode,)) assert self.check(file=1) # svn cat returns an empty file otherwise if self.rev is None: @@ -111,17 +111,17 @@ class SvnCommandPath(svncommon.SvnPathBase): """ return the directory path of the current path joined with any given path arguments. """ - l = self.strpath.split(self.sep) - if len(l) < 4: - raise py.error.EINVAL(self, "base is not valid") - elif len(l) == 4: - return self.join(*args, **kwargs) - else: + l = self.strpath.split(self.sep) + if len(l) < 4: + raise py.error.EINVAL(self, "base is not valid") + elif len(l) == 4: + return self.join(*args, **kwargs) + else: return self.new(basename='').join(*args, **kwargs) # modifying methods (cache must be invalidated) def mkdir(self, *args, **kwargs): - """ create & return the directory joined with args. + """ create & return the directory joined with args. pass a 'msg' keyword argument to set the commit message. """ commit_msg = kwargs.get('msg', "mkdir by py lib invocation") @@ -177,29 +177,29 @@ checkin message msg.""" if getattr(self, 'rev', None) is not None: raise py.error.EINVAL(self, "revisions are immutable") target = self.join(*args) - dir = kwargs.get('dir', 0) - for x in target.parts(reverse=True): - if x.check(): - break - else: - raise py.error.ENOENT(target, "has not any valid base!") - if x == target: - if not x.check(dir=dir): - raise dir and py.error.ENOTDIR(x) or py.error.EISDIR(x) - return x - tocreate = target.relto(x) + dir = kwargs.get('dir', 0) + for x in target.parts(reverse=True): + if x.check(): + break + else: + raise py.error.ENOENT(target, "has not any valid base!") + if x == target: + if not x.check(dir=dir): + raise dir and py.error.ENOTDIR(x) or py.error.EISDIR(x) + return x + tocreate = target.relto(x) basename = tocreate.split(self.sep, 1)[0] tempdir = py.path.local.mkdtemp() - try: - tempdir.ensure(tocreate, dir=dir) + try: + tempdir.ensure(tocreate, dir=dir) cmd = 'svn import -m "%s" "%s" "%s"' % ( - "ensure %s" % self._escape(tocreate), - self._escape(tempdir.join(basename)), + "ensure %s" % self._escape(tocreate), + self._escape(tempdir.join(basename)), x.join(basename)._encodedurl()) - self._svncmdexecauth(cmd) + self._svncmdexecauth(cmd) self._norev_delentry(x) - finally: - tempdir.remove() + finally: + tempdir.remove() return target # end of modifying methods @@ -247,7 +247,7 @@ checkin message msg.""" for lsline in lines: if lsline: info = InfoSvnCommand(lsline) - if info._name != '.': # svn 1.5 produces '.' dirs, + if info._name != '.': # svn 1.5 produces '.' dirs, nameinfo_seq.append((info._name, info)) nameinfo_seq.sort() return nameinfo_seq diff --git a/py/_path/svnwc.py b/py/_path/svnwc.py index 5a25d0f23..233161b36 100644 --- a/py/_path/svnwc.py +++ b/py/_path/svnwc.py @@ -75,13 +75,13 @@ class RepoCache: repositories = RepoCache() -# svn support code +# svn support code ALLOWED_CHARS = "_ -/\\=$.~+%" #add characters as necessary when tested if sys.platform == "win32": ALLOWED_CHARS += ":" ALLOWED_CHARS_HOST = ALLOWED_CHARS + '@:' - + def _getsvnversion(ver=[]): try: return ver[0] @@ -108,7 +108,7 @@ def _check_for_bad_chars(text, allowed_chars=ALLOWED_CHARS): return False def checkbadchars(url): - # (hpk) not quite sure about the exact purpose, guido w.? + # (hpk) not quite sure about the exact purpose, guido w.? proto, uri = url.split("://", 1) if proto != "file": host, uripath = uri.split('/', 1) @@ -116,7 +116,7 @@ def checkbadchars(url): if (_check_for_bad_chars(host, ALLOWED_CHARS_HOST) \ or _check_for_bad_chars(uripath, ALLOWED_CHARS)): raise ValueError("bad char in %r" % (url, )) - + #_______________________________________________________________ @@ -351,7 +351,7 @@ def path_to_fspath(path, addat=True): elif addat: sp = '%s@HEAD' % (sp,) return sp - + def url_from_path(path): fspath = path_to_fspath(path, False) quote = py.std.urllib.quote @@ -460,7 +460,7 @@ class SvnWCCommandPath(common.PathBase): args = args and list(args) or [] args.append(self._makeauthoptions()) return self._svn(cmd, *args) - + def _svn(self, cmd, *args): l = ['svn %s' % cmd] args = [self._escape(item) for item in args] @@ -482,9 +482,9 @@ class SvnWCCommandPath(common.PathBase): except py.process.cmdexec.Error: e = sys.exc_info()[1] strerr = e.err.lower() - if strerr.find('file not found') != -1: - raise py.error.ENOENT(self) - if (strerr.find('file exists') != -1 or + if strerr.find('file not found') != -1: + raise py.error.ENOENT(self) + if (strerr.find('file exists') != -1 or strerr.find('file already exists') != -1 or strerr.find("can't create directory") != -1): raise py.error.EEXIST(self) @@ -503,7 +503,7 @@ class SvnWCCommandPath(common.PathBase): if rev is None or rev == -1: if (py.std.sys.platform != 'win32' and _getsvnversion() == '1.3'): - url += "@HEAD" + url += "@HEAD" else: if _getsvnversion() == '1.3': url += "@%d" % rev @@ -544,7 +544,7 @@ class SvnWCCommandPath(common.PathBase): if p.check(): if p.check(versioned=False): p.add() - return p + return p if kwargs.get('dir', 0): return p._ensuredirs() parent = p.dirpath() @@ -594,7 +594,7 @@ class SvnWCCommandPath(common.PathBase): if not out: # warning or error, raise exception raise Exception(out[4:]) - + def unlock(self): """ unset a previously set lock """ out = self._authsvn('unlock').strip() @@ -627,8 +627,8 @@ class SvnWCCommandPath(common.PathBase): rec = '--non-recursive' # XXX does not work on all subversion versions - #if not externals: - # externals = '--ignore-externals' + #if not externals: + # externals = '--ignore-externals' if updates: updates = '-u' @@ -688,19 +688,19 @@ class SvnWCCommandPath(common.PathBase): del cache.info[self] except KeyError: pass - if out: + if out: m = self._rex_commit.match(out) return int(m.group(1)) def propset(self, name, value, *args): """ set property name to value on this path. """ - d = py.path.local.mkdtemp() - try: - p = d.join('value') - p.write(value) + d = py.path.local.mkdtemp() + try: + p = d.join('value') + p.write(value) self._svn('propset', name, '--file', str(p), *args) - finally: - d.remove() + finally: + d.remove() def propget(self, name): """ get property name on this path. """ @@ -776,16 +776,16 @@ recursively. """ # XXX SVN 1.3 has output on stderr instead of stdout (while it does # return 0!), so a bit nasty, but we assume no output is output # to stderr... - if (output.strip() == '' or + if (output.strip() == '' or output.lower().find('not a versioned resource') != -1): raise py.error.ENOENT(self, output) info = InfoSvnWCCommand(output) # Can't reliably compare on Windows without access to win32api - if py.std.sys.platform != 'win32': - if info.path != self.localpath: - raise py.error.ENOENT(self, "not a versioned resource:" + - " %s != %s" % (info.path, self.localpath)) + if py.std.sys.platform != 'win32': + if info.path != self.localpath: + raise py.error.ENOENT(self, "not a versioned resource:" + + " %s != %s" % (info.path, self.localpath)) cache.info[self] = info return info @@ -799,7 +799,7 @@ recursively. """ fil = common.FNMatcher(fil) # XXX unify argument naming with LocalPath.listdir def notsvn(path): - return path.basename != '.svn' + return path.basename != '.svn' paths = [] for localpath in self.localpath.listdir(notsvn): @@ -823,8 +823,8 @@ recursively. """ def versioned(self): try: s = self.svnwcpath.info() - except (py.error.ENOENT, py.error.EEXIST): - return False + except (py.error.ENOENT, py.error.EEXIST): + return False except py.process.cmdexec.Error: e = sys.exc_info()[1] if e.err.find('is not a working copy')!=-1: @@ -833,7 +833,7 @@ recursively. """ return False raise else: - return True + return True def log(self, rev_start=None, rev_end=1, verbose=False): """ return a list of LogEntry instances for this path. @@ -859,9 +859,9 @@ if verbose is True, then the LogEntry instances also know which files changed. cmd = locale_env + 'svn log --xml %s %s %s "%s"' % ( rev_opt, verbose_opt, auth_opt, self.strpath) - popen = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + popen = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True, ) stdout, stderr = popen.communicate() diff --git a/py/_plugin/hookspec.py b/py/_plugin/hookspec.py index 37230671b..04e1bd0d2 100644 --- a/py/_plugin/hookspec.py +++ b/py/_plugin/hookspec.py @@ -1,9 +1,9 @@ """ -hook specifications for py.test plugins +hook specifications for py.test plugins """ # ------------------------------------------------------------------------- -# Command line and configuration +# Command line and configuration # ------------------------------------------------------------------------- def pytest_namespace(): @@ -16,8 +16,8 @@ def pytest_addhooks(pluginmanager): "add hooks via pluginmanager.registerhooks(module)" def pytest_configure(config): - """ called after command line options have been parsed. - and all plugins and initial conftest files been loaded. + """ called after command line options have been parsed. + and all plugins and initial conftest files been loaded. """ def pytest_unconfigure(config): @@ -28,9 +28,9 @@ def pytest_unconfigure(config): # ------------------------------------------------------------------------- def pytest_ignore_collect(path, config): - """ return true value to prevent considering this path for collection. + """ return true value to prevent considering this path for collection. This hook is consulted for all files and directories prior to considering - collection hooks. + collection hooks. """ pytest_ignore_collect.firstresult = True @@ -51,10 +51,10 @@ def pytest_deselected(items): """ called for test items deselected by keyword. """ def pytest_make_collect_report(collector): - """ perform a collection and return a collection. """ + """ perform a collection and return a collection. """ pytest_make_collect_report.firstresult = True -# XXX rename to item_collected()? meaning in distribution context? +# XXX rename to item_collected()? meaning in distribution context? def pytest_itemstart(item, node=None): """ test item gets collected. """ @@ -63,9 +63,9 @@ def pytest_itemstart(item, node=None): # ------------------------------------------------------------------------- def pytest_pycollect_makemodule(path, parent): - """ return a Module collector or None for the given path. - This hook will be called for each matching test module path. - The pytest_collect_file hook needs to be used if you want to + """ return a Module collector or None for the given path. + This hook will be called for each matching test module path. + The pytest_collect_file hook needs to be used if you want to create test modules for files that do not match as a test module. """ pytest_pycollect_makemodule.firstresult = True @@ -82,7 +82,7 @@ def pytest_generate_tests(metafunc): """ generate (multiple) parametrized calls to a test function.""" # ------------------------------------------------------------------------- -# generic runtest related hooks +# generic runtest related hooks # ------------------------------------------------------------------------- def pytest_runtest_protocol(item): @@ -90,20 +90,20 @@ def pytest_runtest_protocol(item): pytest_runtest_protocol.firstresult = True def pytest_runtest_setup(item): - """ called before pytest_runtest_call(). """ + """ called before pytest_runtest_call(). """ def pytest_runtest_call(item): - """ execute test item. """ + """ execute test item. """ def pytest_runtest_teardown(item): - """ called after pytest_runtest_call(). """ + """ called after pytest_runtest_call(). """ def pytest_runtest_makereport(item, call): """ make a test report for the given item and call outcome. """ pytest_runtest_makereport.firstresult = True def pytest_runtest_logreport(report): - """ process item test report. """ + """ process item test report. """ # special handling for final teardown - somewhat internal for now def pytest__teardown_final(session): @@ -111,10 +111,10 @@ def pytest__teardown_final(session): pytest__teardown_final.firstresult = True def pytest__teardown_final_logerror(report): - """ called if runtest_teardown_final failed. """ + """ called if runtest_teardown_final failed. """ # ------------------------------------------------------------------------- -# test session related hooks +# test session related hooks # ------------------------------------------------------------------------- def pytest_sessionstart(session): @@ -144,7 +144,7 @@ def pytest_report_iteminfo(item): pytest_report_iteminfo.firstresult = True # ------------------------------------------------------------------------- -# doctest hooks +# doctest hooks # ------------------------------------------------------------------------- def pytest_doctest_prepare_content(content): @@ -153,7 +153,7 @@ pytest_doctest_prepare_content.firstresult = True # ------------------------------------------------------------------------- -# error handling and internal debugging hooks +# error handling and internal debugging hooks # ------------------------------------------------------------------------- def pytest_plugin_registered(plugin, manager): @@ -169,4 +169,4 @@ def pytest_keyboard_interrupt(excinfo): """ called for keyboard interrupt. """ def pytest_trace(category, msg): - """ called for debug info. """ + """ called for debug info. """ diff --git a/py/_plugin/pytest__pytest.py b/py/_plugin/pytest__pytest.py index f84a0d67b..5d82edf63 100644 --- a/py/_plugin/pytest__pytest.py +++ b/py/_plugin/pytest__pytest.py @@ -7,20 +7,20 @@ def pytest_funcarg___pytest(request): class PytestArg: def __init__(self, request): - self.request = request + self.request = request def gethookrecorder(self, hook): hookrecorder = HookRecorder(hook._registry) hookrecorder.start_recording(hook._hookspecs) self.request.addfinalizer(hookrecorder.finish_recording) - return hookrecorder + return hookrecorder class ParsedCall: def __init__(self, name, locals): - assert '_name' not in locals + assert '_name' not in locals self.__dict__.update(locals) self.__dict__.pop('self') - self._name = name + self._name = name def __repr__(self): d = self.__dict__.copy() @@ -32,21 +32,21 @@ class HookRecorder: self._registry = registry self.calls = [] self._recorders = {} - + def start_recording(self, hookspecs): if not isinstance(hookspecs, (list, tuple)): hookspecs = [hookspecs] for hookspec in hookspecs: - assert hookspec not in self._recorders - class RecordCalls: - _recorder = self + assert hookspec not in self._recorders + class RecordCalls: + _recorder = self for name, method in vars(hookspec).items(): if name[0] != "_": setattr(RecordCalls, name, self._makecallparser(method)) recorder = RecordCalls() self._recorders[hookspec] = recorder self._registry.register(recorder) - self.hook = HookRelay(hookspecs, registry=self._registry, + self.hook = HookRelay(hookspecs, registry=self._registry, prefix="pytest_") def finish_recording(self): @@ -58,14 +58,14 @@ class HookRecorder: name = method.__name__ args, varargs, varkw, default = py.std.inspect.getargspec(method) if not args or args[0] != "self": - args.insert(0, 'self') + args.insert(0, 'self') fspec = py.std.inspect.formatargspec(args, varargs, varkw, default) # we use exec because we want to have early type # errors on wrong input arguments, using # *args/**kwargs delays this and gives errors # elsewhere exec (py.code.compile(""" - def %(name)s%(fspec)s: + def %(name)s%(fspec)s: self._recorder.calls.append( ParsedCall(%(name)r, locals())) """ % locals())) @@ -91,7 +91,7 @@ class HookRecorder: for i, call in enumerate(self.calls): if call._name == name: del self.calls[i] - return call + return call raise ValueError("could not find call %r" %(name, )) def getcall(self, name): diff --git a/py/_plugin/pytest_assertion.py b/py/_plugin/pytest_assertion.py index c4e221319..f18350e7c 100644 --- a/py/_plugin/pytest_assertion.py +++ b/py/_plugin/pytest_assertion.py @@ -3,15 +3,15 @@ import sys def pytest_addoption(parser): group = parser.getgroup("debugconfig") - group._addoption('--no-assert', action="store_true", default=False, - dest="noassert", + group._addoption('--no-assert', action="store_true", default=False, + dest="noassert", help="disable python assert expression reinterpretation."), def pytest_configure(config): if not config.getvalue("noassert") and not config.getvalue("nomagic"): warn_about_missing_assertion() config._oldassertion = py.builtin.builtins.AssertionError - py.builtin.builtins.AssertionError = py.code._AssertionError + py.builtin.builtins.AssertionError = py.code._AssertionError def pytest_unconfigure(config): if hasattr(config, '_oldassertion'): diff --git a/py/_plugin/pytest_capture.py b/py/_plugin/pytest_capture.py index eb3c60342..d0eb247cf 100644 --- a/py/_plugin/pytest_capture.py +++ b/py/_plugin/pytest_capture.py @@ -1,27 +1,27 @@ """ -configurable per-test stdout/stderr capturing mechanisms. +configurable per-test stdout/stderr capturing mechanisms. -This plugin captures stdout/stderr output for each test separately. -In case of test failures this captured output is shown grouped -togtther with the test. +This plugin captures stdout/stderr output for each test separately. +In case of test failures this captured output is shown grouped +togtther with the test. The plugin also provides test function arguments that help to -assert stdout/stderr output from within your tests, see the -`funcarg example`_. +assert stdout/stderr output from within your tests, see the +`funcarg example`_. -Capturing of input/output streams during tests +Capturing of input/output streams during tests --------------------------------------------------- By default ``sys.stdout`` and ``sys.stderr`` are substituted with -temporary streams during the execution of tests and setup/teardown code. -During the whole testing process it will re-use the same temporary +temporary streams during the execution of tests and setup/teardown code. +During the whole testing process it will re-use the same temporary streams allowing to play well with the logging module which easily -takes ownership on these streams. +takes ownership on these streams. -Also, 'sys.stdin' is substituted with a file-like "null" object that +Also, 'sys.stdin' is substituted with a file-like "null" object that does not return any values. This is to immediately error out -on tests that wait on reading something from stdin. +on tests that wait on reading something from stdin. You can influence output capturing mechanisms from the command line:: @@ -34,34 +34,34 @@ If you set capturing values in a conftest file like this:: # conftest.py option_capture = 'fd' -then all tests in that directory will execute with "fd" style capturing. +then all tests in that directory will execute with "fd" style capturing. -sys-level capturing +sys-level capturing ------------------------------------------ -Capturing on 'sys' level means that ``sys.stdout`` and ``sys.stderr`` -will be replaced with in-memory files (``py.io.TextIO`` to be precise) +Capturing on 'sys' level means that ``sys.stdout`` and ``sys.stderr`` +will be replaced with in-memory files (``py.io.TextIO`` to be precise) that capture writes and decode non-unicode strings to a unicode object -(using a default, usually, UTF-8, encoding). +(using a default, usually, UTF-8, encoding). FD-level capturing and subprocesses ------------------------------------------ The ``fd`` based method means that writes going to system level files -based on the standard file descriptors will be captured, for example -writes such as ``os.write(1, 'hello')`` will be captured properly. -Capturing on fd-level will include output generated from -any subprocesses created during a test. +based on the standard file descriptors will be captured, for example +writes such as ``os.write(1, 'hello')`` will be captured properly. +Capturing on fd-level will include output generated from +any subprocesses created during a test. .. _`funcarg example`: Example Usage of the capturing Function arguments --------------------------------------------------- -You can use the `capsys funcarg`_ and `capfd funcarg`_ to +You can use the `capsys funcarg`_ and `capfd funcarg`_ to capture writes to stdout and stderr streams. Using the -funcargs frees your test from having to care about setting/resetting -the old streams and also interacts well with py.test's own +funcargs frees your test from having to care about setting/resetting +the old streams and also interacts well with py.test's own per-test capturing. Here is an example test function: .. sourcecode:: python @@ -74,14 +74,14 @@ per-test capturing. Here is an example test function: assert err == "world\\n" print "next" out, err = capsys.readouterr() - assert out == "next\\n" + assert out == "next\\n" -The ``readouterr()`` call snapshots the output so far - -and capturing will be continued. After the test -function finishes the original streams will -be restored. If you want to capture on +The ``readouterr()`` call snapshots the output so far - +and capturing will be continued. After the test +function finishes the original streams will +be restored. If you want to capture on the filedescriptor level you can use the ``capfd`` function -argument which offers the same interface. +argument which offers the same interface. """ import py @@ -92,7 +92,7 @@ def pytest_addoption(parser): group._addoption('--capture', action="store", default=None, metavar="method", type="choice", choices=['fd', 'sys', 'no'], help="per-test capturing method: one of fd (default)|sys|no.") - group._addoption('-s', action="store_const", const="no", dest="capture", + group._addoption('-s', action="store_const", const="no", dest="capture", help="shortcut for --capture=no.") def addouterr(rep, outerr): @@ -120,14 +120,14 @@ class CaptureManager: def _maketempfile(self): f = py.std.tempfile.TemporaryFile() - newf = py.io.dupfile(f, encoding="UTF-8") + newf = py.io.dupfile(f, encoding="UTF-8") return newf def _makestringio(self): - return py.io.TextIO() + return py.io.TextIO() def _getcapture(self, method): - if method == "fd": + if method == "fd": return py.io.StdCaptureFD(now=False, out=self._maketempfile(), err=self._maketempfile() ) @@ -144,12 +144,12 @@ class CaptureManager: if config.option.capture: method = config.option.capture else: - try: + try: method = config._conftest.rget("option_capture", path=fspath) except KeyError: method = "fd" - if method == "fd" and not hasattr(os, 'dup'): # e.g. jython - method = "sys" + if method == "fd" and not hasattr(os, 'dup'): # e.g. jython + method = "sys" return method def resumecapture_item(self, item): @@ -160,10 +160,10 @@ class CaptureManager: def resumecapture(self, method): if hasattr(self, '_capturing'): - raise ValueError("cannot resume, already capturing with %r" % + raise ValueError("cannot resume, already capturing with %r" % (self._capturing,)) cap = self._method2capture.get(method) - self._capturing = method + self._capturing = method if cap is None: self._method2capture[method] = cap = self._getcapture(method) cap.startall() @@ -179,9 +179,9 @@ class CaptureManager: outerr = cap.suspend() del self._capturing if item: - outerr = (item.outerr[0] + outerr[0], + outerr = (item.outerr[0] + outerr[0], item.outerr[1] + outerr[1]) - return outerr + return outerr return "", "" def activate_funcargs(self, pyfuncitem): @@ -245,23 +245,23 @@ class CaptureManager: addouterr(rep, outerr) if not rep.passed or rep.when == "teardown": outerr = ('', '') - item.outerr = outerr + item.outerr = outerr return rep def pytest_funcarg__capsys(request): - """captures writes to sys.stdout/sys.stderr and makes - them available successively via a ``capsys.readouterr()`` method - which returns a ``(out, err)`` tuple of captured snapshot strings. - """ + """captures writes to sys.stdout/sys.stderr and makes + them available successively via a ``capsys.readouterr()`` method + which returns a ``(out, err)`` tuple of captured snapshot strings. + """ return CaptureFuncarg(request, py.io.StdCapture) def pytest_funcarg__capfd(request): - """captures writes to file descriptors 1 and 2 and makes - snapshotted ``(out, err)`` string tuples available + """captures writes to file descriptors 1 and 2 and makes + snapshotted ``(out, err)`` string tuples available via the ``capsys.readouterr()`` method. If the underlying platform does not have ``os.dup`` (e.g. Jython) tests using - this funcarg will automatically skip. - """ + this funcarg will automatically skip. + """ if not hasattr(os, 'dup'): py.test.skip("capfd funcarg needs os.dup") return CaptureFuncarg(request, py.io.StdCaptureFD) @@ -279,7 +279,7 @@ class CaptureFuncarg: def _finalize(self): if hasattr(self, 'capture'): self.capture.reset() - del self.capture + del self.capture def readouterr(self): return self.capture.readouterr() diff --git a/py/_plugin/pytest_default.py b/py/_plugin/pytest_default.py index 287331736..2ced855a0 100644 --- a/py/_plugin/pytest_default.py +++ b/py/_plugin/pytest_default.py @@ -1,11 +1,11 @@ -""" default hooks and general py.test options. """ +""" default hooks and general py.test options. """ import sys import py def pytest_pyfunc_call(__multicall__, pyfuncitem): if not __multicall__.execute(): - testfunction = pyfuncitem.obj + testfunction = pyfuncitem.obj if pyfuncitem._isyieldedfunction(): testfunction(*pyfuncitem._args) else: @@ -13,7 +13,7 @@ def pytest_pyfunc_call(__multicall__, pyfuncitem): testfunction(**funcargs) def pytest_collect_file(path, parent): - ext = path.ext + ext = path.ext pb = path.purebasename if pb.startswith("test_") or pb.endswith("_test") or \ path in parent.config._argfspaths: @@ -29,13 +29,13 @@ def pytest_funcarg__pytestconfig(request): return request.config def pytest_ignore_collect(path, config): - ignore_paths = config.getconftest_pathlist("collect_ignore", path=path) + ignore_paths = config.getconftest_pathlist("collect_ignore", path=path) ignore_paths = ignore_paths or [] excludeopt = config.getvalue("ignore") if excludeopt: ignore_paths.extend([py.path.local(x) for x in excludeopt]) return path in ignore_paths - # XXX more refined would be: + # XXX more refined would be: if ignore_paths: for p in ignore_paths: if path == p or path.relto(p): @@ -43,18 +43,18 @@ def pytest_ignore_collect(path, config): def pytest_collect_directory(path, parent): - # XXX reconsider the following comment - # not use parent.Directory here as we generally - # want dir/conftest.py to be able to - # define Directory(dir) already - if not parent.recfilter(path): # by default special ".cvs", ... + # XXX reconsider the following comment + # not use parent.Directory here as we generally + # want dir/conftest.py to be able to + # define Directory(dir) already + if not parent.recfilter(path): # by default special ".cvs", ... # check if cmdline specified this dir or a subdir directly for arg in parent.config._argfspaths: if path == arg or arg.relto(path): break else: - return - Directory = parent.config._getcollectclass('Directory', path) + return + Directory = parent.config._getcollectclass('Directory', path) return Directory(path, parent=parent) def pytest_report_iteminfo(item): @@ -63,7 +63,7 @@ def pytest_report_iteminfo(item): def pytest_addoption(parser): group = parser.getgroup("general", "running and selection options") group._addoption('-x', '--exitfirst', action="store_true", default=False, - dest="exitfirst", + dest="exitfirst", help="exit instantly on first error or failed test."), group._addoption('--maxfail', metavar="num", action="store", type="int", dest="maxfail", default=0, @@ -79,13 +79,13 @@ def pytest_addoption(parser): group.addoption('--collectonly', action="store_true", dest="collectonly", help="only collect tests, don't execute them."), - group.addoption("--ignore", action="append", metavar="path", + group.addoption("--ignore", action="append", metavar="path", help="ignore path during collection (multi-allowed).") - 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 process debugging and configuration") group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir", help="base temporary directory for this test run.") @@ -101,9 +101,9 @@ def setsession(config): if val("collectonly"): from py._test.session import Session config.setsessionclass(Session) - + # pycollect related hooks and code, should move to pytest_pycollect.py - + def pytest_pycollect_makeitem(__multicall__, collector, name, obj): res = __multicall__.execute() if res is not None: @@ -111,21 +111,21 @@ def pytest_pycollect_makeitem(__multicall__, collector, name, obj): if collector._istestclasscandidate(name, obj): res = collector._deprecated_join(name) if res is not None: - return res + return res return collector.Class(name, parent=collector) elif collector.funcnamefilter(name) and hasattr(obj, '__call__'): res = collector._deprecated_join(name) if res is not None: - return res + return res if is_generator(obj): - # XXX deprecation warning + # XXX deprecation warning return collector.Generator(name, parent=collector) else: - return collector._genfunctions(name, obj) + return collector._genfunctions(name, obj) def is_generator(func): try: - return py.code.getrawcode(func).co_flags & 32 # generator function + return py.code.getrawcode(func).co_flags & 32 # generator function except AttributeError: # builtin functions have no bytecode # assume them to not be generators - return False + return False diff --git a/py/_plugin/pytest_doctest.py b/py/_plugin/pytest_doctest.py index 1f30d217b..20f19b2a0 100644 --- a/py/_plugin/pytest_doctest.py +++ b/py/_plugin/pytest_doctest.py @@ -1,10 +1,10 @@ """ -collect and execute doctests from modules and test files. +collect and execute doctests from modules and test files. Usage ------------- -By default all files matching the ``test*.txt`` pattern will +By default all files matching the ``test*.txt`` pattern will be run through the python standard ``doctest`` module. Issue:: py.test --doctest-glob='*.rst' @@ -14,10 +14,10 @@ tests in all python modules (including regular python test modules):: py.test --doctest-modules -You can also make these changes permanent in your project by +You can also make these changes permanent in your project by putting them into a conftest.py file like this:: - # content of conftest.py + # content of conftest.py option_doctestmodules = True option_doctestglob = "*.rst" """ @@ -28,8 +28,8 @@ import doctest def pytest_addoption(parser): group = parser.getgroup("collect") - group.addoption("--doctest-modules", - action="store_true", default=False, + group.addoption("--doctest-modules", + action="store_true", default=False, help="run doctests in all .py modules", dest="doctestmodules") group.addoption("--doctest-glob", @@ -53,44 +53,44 @@ class ReprFailDoctest(TerminalRepr): for line in self.lines: tw.line(line) self.reprlocation.toterminal(tw) - + class DoctestItem(py.test.collect.Item): def __init__(self, path, parent): name = self.__class__.__name__ + ":" + path.basename super(DoctestItem, self).__init__(name=name, parent=parent) - self.fspath = path + self.fspath = path def repr_failure(self, excinfo): if excinfo.errisinstance(doctest.DocTestFailure): doctestfailure = excinfo.value example = doctestfailure.example test = doctestfailure.test - filename = test.filename + filename = test.filename lineno = test.lineno + example.lineno + 1 message = excinfo.type.__name__ reprlocation = ReprFileLocation(filename, lineno, message) - checker = doctest.OutputChecker() + checker = doctest.OutputChecker() REPORT_UDIFF = doctest.REPORT_UDIFF filelines = py.path.local(filename).readlines(cr=0) - i = max(test.lineno, max(0, lineno - 10)) # XXX? + i = max(test.lineno, max(0, lineno - 10)) # XXX? lines = [] for line in filelines[i:lineno]: lines.append("%03d %s" % (i+1, line)) i += 1 - lines += checker.output_difference(example, + lines += checker.output_difference(example, doctestfailure.got, REPORT_UDIFF).split("\n") return ReprFailDoctest(reprlocation, lines) elif excinfo.errisinstance(doctest.UnexpectedException): excinfo = py.code.ExceptionInfo(excinfo.value.exc_info) return super(DoctestItem, self).repr_failure(excinfo) - else: + else: return super(DoctestItem, self).repr_failure(excinfo) class DoctestTextfile(DoctestItem): def runtest(self): if not self._deprecated_testexecution(): failed, tot = doctest.testfile( - str(self.fspath), module_relative=False, + str(self.fspath), module_relative=False, raise_on_error=True, verbose=0) class DoctestModule(DoctestItem): diff --git a/py/_plugin/pytest_genscript.py b/py/_plugin/pytest_genscript.py index 531c8795f..3cb710c0c 100755 --- a/py/_plugin/pytest_genscript.py +++ b/py/_plugin/pytest_genscript.py @@ -1,14 +1,14 @@ #! /usr/bin/env python """ -generate standalone test script to be distributed along with an application. +generate standalone test script to be distributed along with an application. """ import os import sys def pytest_addoption(parser): group = parser.getgroup("debugconfig") - group.addoption("--genscript", action="store", default=None, - dest="genscript", metavar="path", + group.addoption("--genscript", action="store", default=None, + dest="genscript", metavar="path", help="create standalone py.test script at given target path.") def pytest_configure(config): @@ -39,7 +39,7 @@ def main(pybasedir, outfile, infile): for f in filenames: if not f.endswith(".py"): continue - + fn = os.path.join(dirpath, f) files.append(fn) diff --git a/py/_plugin/pytest_helpconfig.py b/py/_plugin/pytest_helpconfig.py index f5f5f7501..3bb51bbcc 100644 --- a/py/_plugin/pytest_helpconfig.py +++ b/py/_plugin/pytest_helpconfig.py @@ -1,14 +1,14 @@ -""" provide version info, conftest/environment config names. +""" provide version info, conftest/environment config names. """ import py import inspect, sys def pytest_addoption(parser): group = parser.getgroup('debugconfig') - group.addoption('--version', action="store_true", + group.addoption('--version', action="store_true", help="display py lib version and import information.") group._addoption('-p', action="append", dest="plugins", default = [], - metavar="name", + metavar="name", help="early-load given plugin (multi-allowed).") group.addoption('--traceconfig', action="store_true", dest="traceconfig", default=False, @@ -19,14 +19,14 @@ def pytest_addoption(parser): group.addoption('--debug', action="store_true", dest="debug", default=False, help="generate and show internal debugging information.") - group.addoption("--help-config", action="store_true", dest="helpconfig", + group.addoption("--help-config", action="store_true", dest="helpconfig", help="show available conftest.py and ENV-variable names.") def pytest_configure(__multicall__, config): if config.option.version: p = py.path.local(py.__file__).dirpath() - sys.stderr.write("This is py.test version %s, imported from %s\n" % + sys.stderr.write("This is py.test version %s, imported from %s\n" % (py.__version__, p)) sys.exit(0) if not config.option.helpconfig: @@ -35,7 +35,7 @@ def pytest_configure(__multicall__, config): options = [] for group in config._parser._groups: options.extend(group.options) - widths = [0] * 10 + widths = [0] * 10 tw = py.io.TerminalWriter() tw.sep("-") tw.line("%-13s | %-18s | %-25s | %s" %( @@ -51,28 +51,28 @@ def pytest_configure(__multicall__, config): optstrings = filter(None, optstrings) optstring = "|".join(optstrings) line = "%-13s | %-18s | %-25s | %s" %( - optstring, - "option_%s" % opt.dest, + optstring, + "option_%s" % opt.dest, "PYTEST_OPTION_%s" % opt.dest.upper(), - opt.help and opt.help or "", + opt.help and opt.help or "", ) tw.line(line[:tw.fullwidth]) for name, help in conftest_options: line = "%-13s | %-18s | %-25s | %s" %( - "", - name, "", - help, + name, + "", + help, ) tw.line(line[:tw.fullwidth]) - + tw.sep("-") sys.exit(0) conftest_options = ( ('pytest_plugins', 'list of plugin names to load'), - ('collect_ignore', '(relative) paths ignored during collection'), - ('rsyncdirs', 'to-be-rsynced directories for dist-testing'), + ('collect_ignore', '(relative) paths ignored during collection'), + ('rsyncdirs', 'to-be-rsynced directories for dist-testing'), ) def pytest_report_header(config): @@ -89,7 +89,7 @@ def pytest_report_header(config): # ===================================================== -# validate plugin syntax and hooks +# validate plugin syntax and hooks # ===================================================== def pytest_plugin_registered(manager, plugin): @@ -97,7 +97,7 @@ def pytest_plugin_registered(manager, plugin): hooks = {} for hookspec in manager.hook._hookspecs: hooks.update(collectattr(hookspec)) - + stringio = py.io.TextIO() def Print(*args): if args: @@ -110,7 +110,7 @@ def pytest_plugin_registered(manager, plugin): #print "checking", name if isgenerichook(name): continue - if name not in hooks: + if name not in hooks: if not getattr(method, 'optionalhook', False): Print("found unknown hook:", name) fail = True @@ -126,10 +126,10 @@ def pytest_plugin_registered(manager, plugin): if arg not in hookargs: Print("argument %r not available" %(arg, )) Print("actual definition: %s" %(formatdef(method))) - Print("available hook arguments: %s" % + Print("available hook arguments: %s" % ", ".join(hookargs)) fail = True - break + break #if not fail: # print "matching hook:", formatdef(method) if fail: @@ -153,12 +153,12 @@ def collectattr(obj, prefixes=("pytest_",)): for apiname in dir(obj): for prefix in prefixes: if apiname.startswith(prefix): - methods[apiname] = getattr(obj, apiname) - return methods + methods[apiname] = getattr(obj, apiname) + return methods def formatdef(func): return "%s%s" %( - func.__name__, + func.__name__, inspect.formatargspec(*inspect.getargspec(func)) ) diff --git a/py/_plugin/pytest_hooklog.py b/py/_plugin/pytest_hooklog.py index 777ac9482..5a45a361b 100644 --- a/py/_plugin/pytest_hooklog.py +++ b/py/_plugin/pytest_hooklog.py @@ -1,8 +1,8 @@ -""" log invocations of extension hooks to a file. """ +""" log invocations of extension hooks to a file. """ import py def pytest_addoption(parser): - parser.addoption("--hooklog", dest="hooklog", default=None, + parser.addoption("--hooklog", dest="hooklog", default=None, help="write hook calls to the given file.") def pytest_configure(config): @@ -10,7 +10,7 @@ def pytest_configure(config): if hooklog: config._hooklogfile = open(hooklog, 'w') config._hooklog_oldperformcall = config.hook._performcall - config.hook._performcall = (lambda name, multicall: + config.hook._performcall = (lambda name, multicall: logged_call(name=name, multicall=multicall, config=config)) def logged_call(name, multicall, config): @@ -26,7 +26,7 @@ def logged_call(name, multicall, config): def pytest_unconfigure(config): try: - del config.hook.__dict__['_performcall'] + del config.hook.__dict__['_performcall'] except KeyError: pass else: diff --git a/py/_plugin/pytest_junitxml.py b/py/_plugin/pytest_junitxml.py index 82910114e..fc1df8fc4 100644 --- a/py/_plugin/pytest_junitxml.py +++ b/py/_plugin/pytest_junitxml.py @@ -1,5 +1,5 @@ """ - logging of test results in JUnit-XML format, for use with Hudson + logging of test results in JUnit-XML format, for use with Hudson and build integration servers. Based on initial code from Ross Lawley. """ @@ -8,10 +8,10 @@ import time def pytest_addoption(parser): group = parser.getgroup("terminal reporting") - group.addoption('--junitxml', action="store", dest="xmlpath", + group.addoption('--junitxml', action="store", dest="xmlpath", metavar="path", default=None, help="create junit-xml style report file at given path.") - group.addoption('--junitprefix', action="store", dest="junitprefix", + group.addoption('--junitprefix', action="store", dest="junitprefix", metavar="str", default=None, help="prepend prefix to classnames in junit-xml output") @@ -24,7 +24,7 @@ def pytest_configure(config): def pytest_unconfigure(config): xml = getattr(config, '_xml', None) if xml: - del config._xml + del config._xml config.pluginmanager.unregister(xml) class LogXML(object): @@ -35,7 +35,7 @@ class LogXML(object): self.passed = self.skipped = 0 self.failed = self.errors = 0 self._durations = {} - + def _opentestcase(self, report): if hasattr(report, 'item'): node = report.item @@ -57,7 +57,7 @@ class LogXML(object): def appendlog(self, fmt, *args): args = tuple([py.xml.escape(arg) for arg in args]) self.test_logs.append(fmt % args) - + def append_pass(self, report): self.passed += 1 self._opentestcase(report) @@ -71,7 +71,7 @@ class LogXML(object): '') self.skipped += 1 else: - self.appendlog('%s', + self.appendlog('%s', report.longrepr) self.failed += 1 self._closetestcase() @@ -79,7 +79,7 @@ class LogXML(object): def append_collect_failure(self, report): self._opentestcase(report) #msg = str(report.longrepr.reprtraceback.extraline) - self.appendlog('%s', + self.appendlog('%s', report.longrepr) self._closetestcase() self.errors += 1 @@ -94,7 +94,7 @@ class LogXML(object): def append_error(self, report): self._opentestcase(report) - self.appendlog('%s', + self.appendlog('%s', report.longrepr) self._closetestcase() self.errors += 1 @@ -103,7 +103,7 @@ class LogXML(object): self._opentestcase(report) if "xfail" in report.keywords: self.appendlog( - '%s', + '%s', report.keywords['xfail']) else: self.appendlog("") @@ -120,14 +120,14 @@ class LogXML(object): self.append_failure(report) elif report.skipped: self.append_skipped(report) - + def pytest_runtest_call(self, item, __multicall__): start = time.time() try: return __multicall__.execute() finally: self._durations[item] = time.time() - start - + def pytest_collectreport(self, report): if not report.passed: if report.failed: @@ -151,7 +151,7 @@ class LogXML(object): logfile = py.std.codecs.open(self.logfile, 'w', encoding='utf-8') else: logfile = open(self.logfile, 'w', encoding='utf-8') - + suite_stop_time = time.time() suite_time_delta = suite_stop_time - self.suite_start_time numtests = self.passed + self.failed diff --git a/py/_plugin/pytest_mark.py b/py/_plugin/pytest_mark.py index f5cd9a7cc..35ba91541 100644 --- a/py/_plugin/pytest_mark.py +++ b/py/_plugin/pytest_mark.py @@ -1,19 +1,19 @@ """ -generic mechanism for marking python functions. +generic mechanism for marking python functions. By using the ``py.test.mark`` helper you can instantiate -decorators that will set named meta data on test functions. +decorators that will set named meta data on test functions. -Marking a single function +Marking a single function ---------------------------------------------------- You can "mark" a test function with meta data like this:: @py.test.mark.webtest def test_send_http(): - ... + ... -This will set a "Marker" instance as a function attribute named "webtest". +This will set a "Marker" instance as a function attribute named "webtest". You can also specify parametrized meta data like this:: @py.test.mark.webtest(firefox=30) @@ -34,7 +34,7 @@ and later access it with ``test_receive.webtest.args[0] == 'triangular``. .. _`scoped-marking`: -Marking whole classes or modules +Marking whole classes or modules ---------------------------------------------------- If you are programming with Python2.6 you may use ``py.test.mark`` decorators @@ -48,9 +48,9 @@ with classes to apply markers to all its test methods:: ... This is equivalent to directly applying the decorator to the -two test functions. +two test functions. -To remain compatible with Python2.5 you can also set a +To remain compatible with Python2.5 you can also set a ``pytestmark`` attribute on a TestClass like this:: import py @@ -70,8 +70,8 @@ You can also set a module level marker:: import py pytestmark = py.test.mark.webtest -in which case it will be applied to all functions and -methods defined in the module. +in which case it will be applied to all functions and +methods defined in the module. Using "-k MARKNAME" to select tests ---------------------------------------------------- @@ -88,8 +88,8 @@ def pytest_namespace(): return {'mark': MarkGenerator()} class MarkGenerator: - """ non-underscore attributes of this object can be used as decorators for - marking test functions. Example: @py.test.mark.slowtest in front of a + """ non-underscore attributes of this object can be used as decorators for + marking test functions. Example: @py.test.mark.slowtest in front of a function will set the 'slowtest' marker object on it. """ def __getattr__(self, name): if name[0] == "_": @@ -109,7 +109,7 @@ class MarkDecorator: return "" %(name, d) def __call__(self, *args, **kwargs): - """ if passed a single callable argument: decorate it with mark info. + """ if passed a single callable argument: decorate it with mark info. otherwise add *args/**kwargs in-place to mark information. """ if args: func = args[0] @@ -120,7 +120,7 @@ class MarkDecorator: l = func.pytestmark if not isinstance(l, list): func.pytestmark = [l, self] - else: + else: l.append(self) else: func.pytestmark = [self] @@ -137,7 +137,7 @@ class MarkDecorator: self.args.extend(args) self.kwargs.update(kwargs) return self - + class MarkInfo: def __init__(self, name, args, kwargs): self._name = name @@ -153,7 +153,7 @@ class MarkInfo: def __repr__(self): return "" % ( self._name, self.args, self.kwargs) - + def pytest_pycollect_makeitem(__multicall__, collector, name, obj): item = __multicall__.execute() @@ -172,5 +172,5 @@ def pytest_pycollect_makeitem(__multicall__, collector, name, obj): if isinstance(mark, MarkDecorator): mark(func) item.keywords.update(py.builtin._getfuncdict(func) or {}) - + return item diff --git a/py/_plugin/pytest_monkeypatch.py b/py/_plugin/pytest_monkeypatch.py index 13c6a6d9a..37fc02e8a 100644 --- a/py/_plugin/pytest_monkeypatch.py +++ b/py/_plugin/pytest_monkeypatch.py @@ -1,54 +1,54 @@ """ -safely patch object attributes, dicts and environment variables. +safely patch object attributes, dicts and environment variables. -Usage +Usage ---------------- -Use the `monkeypatch funcarg`_ to tweak your global test environment -for running a particular test. You can safely set/del an attribute, +Use the `monkeypatch funcarg`_ to tweak your global test environment +for running a particular test. You can safely set/del an attribute, dictionary item or environment variable by respective methods -on the monkeypatch funcarg. If you want e.g. to set an ENV1 variable -and have os.path.expanduser return a particular directory, you can +on the monkeypatch funcarg. If you want e.g. to set an ENV1 variable +and have os.path.expanduser return a particular directory, you can write it down like this: -.. sourcecode:: python +.. sourcecode:: python def test_mytest(monkeypatch): monkeypatch.setenv('ENV1', 'myval') monkeypatch.setattr(os.path, 'expanduser', lambda x: '/tmp/xyz') ... # your test code that uses those patched values implicitely -After the test function finished all modifications will be undone, -because the ``monkeypatch.undo()`` method is registered as a finalizer. +After the test function finished all modifications will be undone, +because the ``monkeypatch.undo()`` method is registered as a finalizer. -``monkeypatch.setattr/delattr/delitem/delenv()`` all -by default raise an Exception if the target does not exist. -Pass ``raising=False`` if you want to skip this check. +``monkeypatch.setattr/delattr/delitem/delenv()`` all +by default raise an Exception if the target does not exist. +Pass ``raising=False`` if you want to skip this check. -prepending to PATH or other environment variables +prepending to PATH or other environment variables --------------------------------------------------------- To prepend a value to an already existing environment parameter: -.. sourcecode:: python +.. sourcecode:: python def test_mypath_finding(monkeypatch): monkeypatch.setenv('PATH', 'x/y', prepend=":") - # in bash language: export PATH=x/y:$PATH + # in bash language: export PATH=x/y:$PATH calling "undo" finalization explicitely ----------------------------------------- At the end of function execution py.test invokes -a teardown hook which undoes all monkeypatch changes. -If you do not want to wait that long you can call +a teardown hook which undoes all monkeypatch changes. +If you do not want to wait that long you can call finalization explicitely:: - monkeypatch.undo() + monkeypatch.undo() This will undo previous changes. This call consumes the undo stack. Calling it a second time has no effect unless -you start monkeypatching after the undo call. +you start monkeypatching after the undo call. .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ """ @@ -56,21 +56,21 @@ you start monkeypatching after the undo call. import py, os, sys def pytest_funcarg__monkeypatch(request): - """The returned ``monkeypatch`` funcarg provides these + """The returned ``monkeypatch`` funcarg provides these helper methods to modify objects, dictionaries or os.environ:: - monkeypatch.setattr(obj, name, value, raising=True) + monkeypatch.setattr(obj, name, value, raising=True) monkeypatch.delattr(obj, name, raising=True) - monkeypatch.setitem(mapping, name, value) + monkeypatch.setitem(mapping, name, value) monkeypatch.delitem(obj, name, raising=True) - monkeypatch.setenv(name, value, prepend=False) + monkeypatch.setenv(name, value, prepend=False) monkeypatch.delenv(name, value, raising=True) monkeypatch.syspath_prepend(path) - All modifications will be undone when the requesting - test function finished its execution. The ``raising`` - parameter determines if a KeyError or AttributeError - will be raised if the set/deletion operation has no target. + All modifications will be undone when the requesting + test function finished its execution. The ``raising`` + parameter determines if a KeyError or AttributeError + will be raised if the set/deletion operation has no target. """ monkeypatch = MonkeyPatch() request.addfinalizer(monkeypatch.undo) @@ -93,7 +93,7 @@ class MonkeyPatch: def delattr(self, obj, name, raising=True): if not hasattr(obj, name): if raising: - raise AttributeError(name) + raise AttributeError(name) else: self._setattr.insert(0, (obj, name, getattr(obj, name, notset))) delattr(obj, name) @@ -105,8 +105,8 @@ class MonkeyPatch: def delitem(self, dic, name, raising=True): if name not in dic: if raising: - raise KeyError(name) - else: + raise KeyError(name) + else: self._setitem.insert(0, (dic, name, dic.get(name, notset))) del dic[name] diff --git a/py/_plugin/pytest_nose.py b/py/_plugin/pytest_nose.py index 244f5b61d..002e1d374 100644 --- a/py/_plugin/pytest_nose.py +++ b/py/_plugin/pytest_nose.py @@ -1,7 +1,7 @@ -"""nose-compatibility plugin: allow to run nose test suites natively. +"""nose-compatibility plugin: allow to run nose test suites natively. -This is an experimental plugin for allowing to run tests written -in 'nosetests style with py.test. +This is an experimental plugin for allowing to run tests written +in 'nosetests style with py.test. Usage ------------- @@ -11,31 +11,31 @@ type:: py.test # instead of 'nosetests' and you should be able to run nose style tests and at the same -time can make full use of py.test's capabilities. +time can make full use of py.test's capabilities. Supported nose Idioms ---------------------- * setup and teardown at module/class/method level -* SkipTest exceptions and markers +* SkipTest exceptions and markers * setup/teardown decorators -* yield-based tests and their setup -* general usage of nose utilities +* yield-based tests and their setup +* general usage of nose utilities Unsupported idioms / issues ---------------------------------- - nose-style doctests are not collected and executed correctly, - also fixtures don't work. + also fixtures don't work. -- no nose-configuration is recognized +- no nose-configuration is recognized -If you find other issues or have suggestions please run:: +If you find other issues or have suggestions please run:: - py.test --pastebin=all + py.test --pastebin=all and send the resulting URL to a py.test contact channel, -at best to the mailing list. +at best to the mailing list. """ import py import inspect @@ -45,28 +45,28 @@ def pytest_runtest_makereport(__multicall__, item, call): SkipTest = getattr(sys.modules.get('nose', None), 'SkipTest', None) if SkipTest: if call.excinfo and call.excinfo.errisinstance(SkipTest): - # let's substitute the excinfo with a py.test.skip one + # let's substitute the excinfo with a py.test.skip one call2 = call.__class__(lambda: py.test.skip(str(call.excinfo.value)), call.when) - call.excinfo = call2.excinfo + call.excinfo = call2.excinfo def pytest_report_iteminfo(item): - # nose 0.11.1 uses decorators for "raises" and other helpers. - # for reporting progress by filename we fish for the filename + # nose 0.11.1 uses decorators for "raises" and other helpers. + # for reporting progress by filename we fish for the filename if isinstance(item, py.test.collect.Function): obj = item.obj if hasattr(obj, 'compat_co_firstlineno'): - fn = sys.modules[obj.__module__].__file__ + fn = sys.modules[obj.__module__].__file__ if fn.endswith(".pyc"): fn = fn[:-1] #assert 0 #fn = inspect.getsourcefile(obj) or inspect.getfile(obj) - lineno = obj.compat_co_firstlineno + lineno = obj.compat_co_firstlineno return py.path.local(fn), lineno, obj.__module__ - + def pytest_runtest_setup(item): if isinstance(item, (py.test.collect.Function)): if isinstance(item.parent, py.test.collect.Generator): - gen = item.parent + gen = item.parent if not hasattr(gen, '_nosegensetup'): call_optional(gen.obj, 'setup') if isinstance(gen.parent, py.test.collect.Instance): diff --git a/py/_plugin/pytest_pastebin.py b/py/_plugin/pytest_pastebin.py index e6a9ba8ab..164457b33 100644 --- a/py/_plugin/pytest_pastebin.py +++ b/py/_plugin/pytest_pastebin.py @@ -1,22 +1,22 @@ """ -submit failure or test session information to a pastebin service. +submit failure or test session information to a pastebin service. Usage ---------- **Creating a URL for each test failure**:: - py.test --pastebin=failed + py.test --pastebin=failed This will submit test run information to a remote Paste service and provide a URL for each failure. You may select tests as usual or add -for example ``-x`` if you only want to send one particular failure. +for example ``-x`` if you only want to send one particular failure. **Creating a URL for a whole test session log**:: - py.test --pastebin=all + py.test --pastebin=all -Currently only pasting to the http://paste.pocoo.org service is implemented. +Currently only pasting to the http://paste.pocoo.org service is implemented. """ import py, sys @@ -29,8 +29,8 @@ class url: def pytest_addoption(parser): group = parser.getgroup("terminal reporting") group._addoption('--pastebin', metavar="mode", - action='store', dest="pastebin", default=None, - type="choice", choices=['failed', 'all'], + action='store', dest="pastebin", default=None, + type="choice", choices=['failed', 'all'], help="send failed|all info to Pocoo pastebin service.") def pytest_configure(__multicall__, config): @@ -39,13 +39,13 @@ def pytest_configure(__multicall__, config): if config.option.pastebin == "all": config._pastebinfile = tempfile.TemporaryFile('w+') tr = config.pluginmanager.getplugin('terminalreporter') - oldwrite = tr._tw.write + oldwrite = tr._tw.write def tee_write(s, **kwargs): oldwrite(s, **kwargs) config._pastebinfile.write(str(s)) - tr._tw.write = tee_write + tr._tw.write = tee_write -def pytest_unconfigure(config): +def pytest_unconfigure(config): if hasattr(config, '_pastebinfile'): config._pastebinfile.seek(0) sessionlog = config._pastebinfile.read() @@ -56,7 +56,7 @@ def pytest_unconfigure(config): sys.stderr.write("pastebin session-log: %s\n" % pastebinurl) tr = config.pluginmanager.getplugin('terminalreporter') del tr._tw.__dict__['write'] - + def getproxy(): return py.std.xmlrpclib.ServerProxy(url.xmlrpc).pastes diff --git a/py/_plugin/pytest_pdb.py b/py/_plugin/pytest_pdb.py index 7bcd5b98d..f508e96f4 100644 --- a/py/_plugin/pytest_pdb.py +++ b/py/_plugin/pytest_pdb.py @@ -5,7 +5,7 @@ import py import pdb, sys, linecache def pytest_addoption(parser): - group = parser.getgroup("general") + group = parser.getgroup("general") group._addoption('--pdb', action="store_true", dest="usepdb", default=False, help="start the interactive Python debugger on errors.") @@ -17,7 +17,7 @@ def pytest_configure(config): class PdbInvoke: def pytest_sessionfinish(self, session): # don't display failures again at the end - session.config.option.tbstyle = "no" + session.config.option.tbstyle = "no" def pytest_runtest_makereport(self, item, call, __multicall__): if not call.excinfo or \ call.excinfo.errisinstance(py.test.skip.Exception): diff --git a/py/_plugin/pytest_pylint.py b/py/_plugin/pytest_pylint.py index b2656ff7e..368aab4cf 100644 --- a/py/_plugin/pytest_pylint.py +++ b/py/_plugin/pytest_pylint.py @@ -4,7 +4,7 @@ XXX: Currently in progress, NOT IN WORKING STATE. """ import py -pylint = py.test.importorskip("pylint.lint") +pylint = py.test.importorskip("pylint.lint") def pytest_addoption(parser): group = parser.getgroup('pylint options') diff --git a/py/_plugin/pytest_pytester.py b/py/_plugin/pytest_pytester.py index ccde0856f..b589e6994 100644 --- a/py/_plugin/pytest_pytester.py +++ b/py/_plugin/pytest_pytester.py @@ -1,5 +1,5 @@ """ -funcargs and support code for testing py.test's own functionality. +funcargs and support code for testing py.test's own functionality. """ import py @@ -53,7 +53,7 @@ class TmpTestdir: def __init__(self, request): self.request = request self._pytest = request.getfuncargvalue("_pytest") - # XXX remove duplication with tmpdir plugin + # XXX remove duplication with tmpdir plugin basetmp = request.config.ensuretemp("testdir") name = request.function.__name__ for i in range(100): @@ -105,7 +105,7 @@ class TmpTestdir: def chdir(self): old = self.tmpdir.chdir() if not hasattr(self, '_olddir'): - self._olddir = old + self._olddir = old def _makefile(self, ext, args, kwargs): items = list(kwargs.items()) @@ -120,7 +120,7 @@ class TmpTestdir: p.write(source.encode("utf-8"), "wb") if ret is None: ret = p - return ret + return ret def makefile(self, ext, *args, **kwargs): @@ -140,7 +140,7 @@ class TmpTestdir: path = self.tmpdir py.std.sys.path.insert(0, str(path)) self._syspathremove.append(str(path)) - + def mkdir(self, name): return self.tmpdir.mkdir(name) @@ -159,12 +159,12 @@ class TmpTestdir: rec = self.getreportrecorder(config) colitems = [config.getnode(arg) for arg in config.args] items = list(session.genitems(colitems)) - return items, rec + return items, rec def runitem(self, source): - # used from runner functional tests + # used from runner functional tests item = self.getitem(source) - # the test class where we are called from wants to provide the runner + # the test class where we are called from wants to provide the runner testclassinstance = py.builtin._getimself(self.request.function) runner = testclassinstance.getrunner() return runner(item) @@ -181,7 +181,7 @@ class TmpTestdir: l = list(args) + [p] reprec = self.inline_run(*l) reports = reprec.getreports("pytest_runtest_logreport") - assert len(reports) == 1, reports + assert len(reports) == 1, reports return reports[0] def inline_run(self, *args): @@ -193,7 +193,7 @@ class TmpTestdir: colitems = config.getinitialnodes() session.main(colitems) config.pluginmanager.do_unconfigure(config) - return reprec + return reprec def config_preparse(self): config = self.Config() @@ -202,7 +202,7 @@ class TmpTestdir: config.pluginmanager.import_plugin(plugin) else: if isinstance(plugin, dict): - plugin = PseudoPlugin(plugin) + plugin = PseudoPlugin(plugin) if not config.pluginmanager.isregistered(plugin): config.pluginmanager.register(plugin) return config @@ -213,21 +213,21 @@ class TmpTestdir: config = self.config_preparse() args = list(args) + ["--basetemp=%s" % self.tmpdir.dirpath('basetemp')] config.parse(args) - return config + return config def reparseconfig(self, args=None): """ this is used from tests that want to re-invoke parse(). """ if not args: args = [self.tmpdir] - from py._test import config + from py._test import config oldconfig = config.config_per_process # py.test.config try: c = config.config_per_process = py.test.config = pytestConfig() c.basetemp = oldconfig.mktemp("reparse", numbered=True) - c.parse(args) + c.parse(args) return c - finally: - config.config_per_process = py.test.config = oldconfig + finally: + config.config_per_process = py.test.config = oldconfig def parseconfigure(self, *args): config = self.parseconfig(*args) @@ -239,7 +239,7 @@ class TmpTestdir: moditems = modcol.collect() for item in modcol.collect(): if item.name == funcname: - return item + return item else: assert 0, "%r item not found in module:\n%s" %(funcname, source) @@ -247,7 +247,7 @@ class TmpTestdir: modcol = self.getmodulecol(source) return list(modcol.config.initsession().genitems([modcol])) #assert item is not None, "%r item not found in module:\n%s" %(funcname, source) - #return item + #return item def getfscol(self, path, configargs=()): self.config = self.parseconfig(path, *configargs) @@ -262,9 +262,9 @@ class TmpTestdir: self.config = self.parseconfig(path, *configargs) self.session = self.config.initsession() #self.config.pluginmanager.do_configure(config=self.config) - # XXX - self.config.pluginmanager.import_plugin("runner") - plugin = self.config.pluginmanager.getplugin("runner") + # XXX + self.config.pluginmanager.import_plugin("runner") + plugin = self.config.pluginmanager.getplugin("runner") plugin.pytest_configure(config=self.config) return self.config.getnode(path) @@ -290,7 +290,7 @@ class TmpTestdir: f1 = p1.open("wb") f2 = p2.open("wb") now = time.time() - popen = self.popen(cmdargs, stdout=f1, stderr=f2, + popen = self.popen(cmdargs, stdout=f1, stderr=f2, close_fds=(sys.platform != "win32")) ret = popen.wait() f1.close() @@ -322,7 +322,7 @@ class TmpTestdir: cmdlinename = scriptname.replace(".", "") assert hasattr(py.cmdline, cmdlinename), cmdlinename source = ("import sys;sys.path.insert(0,%r);" - "import py;py.cmdline.%s()" % + "import py;py.cmdline.%s()" % (str(py._pydir.dirpath()), cmdlinename)) return (sys.executable, "-c", source,) @@ -344,9 +344,9 @@ class TmpTestdir: return self.run(py.std.sys.executable, "-c", command) def runpytest(self, *args): - p = py.path.local.make_numbered_dir(prefix="runpytest-", + p = py.path.local.make_numbered_dir(prefix="runpytest-", keep=None, rootdir=self.tmpdir) - args = ('--basetemp=%s' % p, ) + args + args = ('--basetemp=%s' % p, ) + args for x in args: if '--confcutdir' in str(x): break @@ -377,7 +377,7 @@ def getdecoded(out): class PseudoPlugin: def __init__(self, vars): - self.__dict__.update(vars) + self.__dict__.update(vars) class ReportRecorder(object): def __init__(self, hook): @@ -395,7 +395,7 @@ class ReportRecorder(object): """ return list of ParsedCall instances matching the given eventname. """ return self.hookrecorder.getcalls(names) - # functionality for test reports + # functionality for test reports def getreports(self, names="pytest_runtest_logreport pytest_collectreport"): return [x.report for x in self.getcalls(names)] @@ -426,14 +426,14 @@ class ReportRecorder(object): skipped = [] failed = [] for rep in self.getreports("pytest_runtest_logreport"): - if rep.passed: - if rep.when == "call": - passed.append(rep) - elif rep.skipped: - skipped.append(rep) + if rep.passed: + if rep.when == "call": + passed.append(rep) + elif rep.skipped: + skipped.append(rep) elif rep.failed: - failed.append(rep) - return passed, skipped, failed + failed.append(rep) + return passed, skipped, failed def countoutcomes(self): return [len(x) for x in self.listoutcomes()] @@ -456,7 +456,7 @@ class LineComp: self.stringio = py.io.TextIO() def assert_contains_lines(self, lines2): - """ assert that lines2 are contained (linearly) in lines1. + """ assert that lines2 are contained (linearly) in lines1. return a list of extralines found. """ __tracebackhide__ = True @@ -465,7 +465,7 @@ class LineComp: self.stringio.seek(0) lines1 = val.split("\n") return LineMatcher(lines1).fnmatch_lines(lines2) - + class LineMatcher: def __init__(self, lines): self.lines = lines @@ -490,7 +490,7 @@ class LineMatcher: nextline = lines1.pop(0) if line == nextline: print_("exact match:", repr(line)) - break + break elif fnmatch(nextline, line): print_("fnmatch:", repr(line)) print_(" with:", repr(nextline)) diff --git a/py/_plugin/pytest_recwarn.py b/py/_plugin/pytest_recwarn.py index 68bf25472..53c686c33 100644 --- a/py/_plugin/pytest_recwarn.py +++ b/py/_plugin/pytest_recwarn.py @@ -1,10 +1,10 @@ """ -helpers for asserting deprecation and other warnings. +helpers for asserting deprecation and other warnings. -Example usage +Example usage --------------------- -You can use the ``recwarn`` funcarg to track +You can use the ``recwarn`` funcarg to track warnings within a test function: .. sourcecode:: python @@ -25,11 +25,11 @@ warning: .. sourcecode:: python import py - + def test_global(): py.test.deprecated_call(myfunction, 17) - - + + """ import py @@ -39,10 +39,10 @@ def pytest_funcarg__recwarn(request): """Return a WarningsRecorder instance that provides these methods: * ``pop(category=None)``: return last warning matching the category. - * ``clear()``: clear list of warnings + * ``clear()``: clear list of warnings """ if sys.version_info >= (2,7): - import warnings + import warnings oldfilters = warnings.filters[:] warnings.simplefilter('default') def reset_filters(): @@ -57,19 +57,19 @@ def pytest_namespace(): def deprecated_call(func, *args, **kwargs): """ assert that calling func(*args, **kwargs) - triggers a DeprecationWarning. - """ + triggers a DeprecationWarning. + """ warningmodule = py.std.warnings l = [] oldwarn_explicit = getattr(warningmodule, 'warn_explicit') - def warn_explicit(*args, **kwargs): - l.append(args) + def warn_explicit(*args, **kwargs): + l.append(args) oldwarn_explicit(*args, **kwargs) oldwarn = getattr(warningmodule, 'warn') - def warn(*args, **kwargs): - l.append(args) + def warn(*args, **kwargs): + l.append(args) oldwarn(*args, **kwargs) - + warningmodule.warn_explicit = warn_explicit warningmodule.warn = warn try: @@ -100,10 +100,10 @@ class WarningsRecorder: self.list.append(RecordedWarning( message, category, filename, lineno, line)) try: - self.old_showwarning(message, category, + self.old_showwarning(message, category, filename, lineno, line=line) except TypeError: - # < python2.6 + # < python2.6 self.old_showwarning(message, category, filename, lineno) self.old_showwarning = warningmodule.showwarning warningmodule.showwarning = showwarning @@ -121,7 +121,7 @@ class WarningsRecorder: # warnings.onceregistry.clear() # warnings.__warningregistry__.clear() - def clear(self): + def clear(self): self.list[:] = [] def finalize(self): diff --git a/py/_plugin/pytest_restdoc.py b/py/_plugin/pytest_restdoc.py index 6f815550d..6bcf06eee 100644 --- a/py/_plugin/pytest_restdoc.py +++ b/py/_plugin/pytest_restdoc.py @@ -1,5 +1,5 @@ """ -perform ReST syntax, local and remote reference tests on .rst/.txt files. +perform ReST syntax, local and remote reference tests on .rst/.txt files. """ import py import sys, os, re @@ -7,8 +7,8 @@ import sys, os, re def pytest_addoption(parser): group = parser.getgroup("ReST", "ReST documentation check options") group.addoption('-R', '--urlcheck', - action="store_true", dest="urlcheck", default=False, - help="urlopen() remote links found in ReST text files.") + action="store_true", dest="urlcheck", default=False, + help="urlopen() remote links found in ReST text files.") group.addoption('--urltimeout', action="store", metavar="secs", type="int", dest="urlcheck_timeout", default=5, help="timeout in seconds for remote urlchecks") @@ -59,7 +59,7 @@ def deindent(s, sep='\n'): lines[i] = line[leastspaces:] return sep.join(lines) -class ReSTSyntaxTest(py.test.collect.Item): +class ReSTSyntaxTest(py.test.collect.Item): def __init__(self, name, parent, project): super(ReSTSyntaxTest, self).__init__(name=name, parent=parent) self.project = project @@ -74,14 +74,14 @@ class ReSTSyntaxTest(py.test.collect.Item): py.test.importorskip("docutils") self.register_linkrole() from docutils.utils import SystemMessage - try: + try: self._checkskip(path, self.project.get_htmloutputpath(path)) self.project.process(path) - except KeyboardInterrupt: - raise - except SystemMessage: - # we assume docutils printed info on stdout - py.test.fail("docutils processing failed, see captured stderr") + except KeyboardInterrupt: + raise + except SystemMessage: + # we assume docutils printed info on stdout + py.test.fail("docutils processing failed, see captured stderr") def register_linkrole(self): #directive.register_linkrole('api', self.resolve_linkrole) @@ -89,7 +89,7 @@ class ReSTSyntaxTest(py.test.collect.Item): # # # XXX fake sphinx' "toctree" and refs # directive.register_linkrole('ref', self.resolve_linkrole) - + from docutils.parsers.rst import directives def toctree_directive(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): @@ -101,7 +101,7 @@ class ReSTSyntaxTest(py.test.collect.Item): self.register_pygments() def register_pygments(self): - # taken from pygments-main/external/rst-directive.py + # taken from pygments-main/external/rst-directive.py from docutils.parsers.rst import directives try: from pygments.formatters import HtmlFormatter @@ -143,7 +143,7 @@ class ReSTSyntaxTest(py.test.collect.Item): def resolve_linkrole(self, name, text, check=True): apigen_relpath = self.project.apigen_relpath - + if name == 'api': if text == 'py': return ('py', apigen_relpath + 'api/index.html') @@ -182,39 +182,39 @@ class ReSTSyntaxTest(py.test.collect.Item): relpath += '.html' return (text, apigen_relpath + 'source/%s' % (relpath,)) elif name == 'ref': - return ("", "") + return ("", "") def _checkskip(self, lpath, htmlpath=None): if not self.config.getvalue("forcegen"): lpath = py.path.local(lpath) if htmlpath is not None: htmlpath = py.path.local(htmlpath) - if lpath.ext == '.txt': + if lpath.ext == '.txt': htmlpath = htmlpath or lpath.new(ext='.html') - if htmlpath.check(file=1) and htmlpath.mtime() >= lpath.mtime(): + if htmlpath.check(file=1) and htmlpath.mtime() >= lpath.mtime(): py.test.skip("html file is up to date, use --forcegen to regenerate") - #return [] # no need to rebuild + #return [] # no need to rebuild -class DoctestText(py.test.collect.Item): +class DoctestText(py.test.collect.Item): def reportinfo(self): return self.fspath, None, "doctest" - def runtest(self): + def runtest(self): content = self._normalize_linesep() newcontent = self.config.hook.pytest_doctest_prepare_content(content=content) if newcontent is not None: - content = newcontent - s = content + content = newcontent + s = content l = [] prefix = '.. >>> ' - mod = py.std.types.ModuleType(self.fspath.purebasename) + mod = py.std.types.ModuleType(self.fspath.purebasename) skipchunk = False for line in deindent(s).split('\n'): stripped = line.strip() if skipchunk and line.startswith(skipchunk): py.builtin.print_("skipping", line) continue - skipchunk = False + skipchunk = False if stripped.startswith(prefix): try: py.builtin.exec_(py.code.Source( @@ -228,9 +228,9 @@ class DoctestText(py.test.collect.Item): else: l.append(line) docstring = "\n".join(l) - mod.__doc__ = docstring + mod.__doc__ = docstring failed, tot = py.std.doctest.testmod(mod, verbose=1) - if failed: + if failed: py.test.fail("doctest %s: %s failed out of %s" %( self.fspath, failed, tot)) @@ -245,43 +245,43 @@ class DoctestText(py.test.collect.Item): linesep = '\r\n' s = s.replace(linesep, '\n') return s - -class LinkCheckerMaker(py.test.collect.Collector): + +class LinkCheckerMaker(py.test.collect.Collector): def collect(self): return list(self.genlinkchecks()) def genlinkchecks(self): path = self.fspath - # generating functions + args as single tests + # generating functions + args as single tests timeout = self.config.getvalue("urlcheck_timeout") - for lineno, line in enumerate(path.readlines()): + for lineno, line in enumerate(path.readlines()): line = line.strip() - if line.startswith('.. _'): + if line.startswith('.. _'): if line.startswith('.. _`'): delim = '`:' else: delim = ':' l = line.split(delim, 1) - if len(l) != 2: + if len(l) != 2: continue - tryfn = l[1].strip() + tryfn = l[1].strip() name = "%s:%d" %(tryfn, lineno) - if tryfn.startswith('http:') or tryfn.startswith('https'): + if tryfn.startswith('http:') or tryfn.startswith('https'): if self.config.getvalue("urlcheck"): - yield CheckLink(name, parent=self, + yield CheckLink(name, parent=self, args=(tryfn, path, lineno, timeout), checkfunc=urlcheck) elif tryfn.startswith('webcal:'): continue - else: - i = tryfn.find('#') - if i != -1: + else: + i = tryfn.find('#') + if i != -1: checkfn = tryfn[:i] - else: - checkfn = tryfn - if checkfn.strip() and (1 or checkfn.endswith('.html')): - yield CheckLink(name, parent=self, + else: + checkfn = tryfn + if checkfn.strip() and (1 or checkfn.endswith('.html')): + yield CheckLink(name, parent=self, args=(tryfn, path, lineno), checkfunc=localrefcheck) - + class CheckLink(py.test.collect.Item): def __init__(self, name, parent, args, checkfunc): super(CheckLink, self).__init__(name, parent) @@ -294,16 +294,16 @@ class CheckLink(py.test.collect.Item): def reportinfo(self, basedir=None): return (self.fspath, self.args[2], "checklink: %s" % self.args[0]) -def urlcheck(tryfn, path, lineno, TIMEOUT_URLOPEN): +def urlcheck(tryfn, path, lineno, TIMEOUT_URLOPEN): old = py.std.socket.getdefaulttimeout() py.std.socket.setdefaulttimeout(TIMEOUT_URLOPEN) try: - try: + try: py.builtin.print_("trying remote", tryfn) py.std.urllib2.urlopen(tryfn) finally: py.std.socket.setdefaulttimeout(old) - except (py.std.urllib2.URLError, py.std.urllib2.HTTPError): + except (py.std.urllib2.URLError, py.std.urllib2.HTTPError): e = sys.exc_info()[1] if getattr(e, 'code', None) in (401, 403): # authorization required, forbidden py.test.skip("%s: %s" %(tryfn, str(e))) @@ -311,38 +311,38 @@ def urlcheck(tryfn, path, lineno, TIMEOUT_URLOPEN): py.test.fail("remote reference error %r in %s:%d\n%s" %( tryfn, path.basename, lineno+1, e)) -def localrefcheck(tryfn, path, lineno): - # assume it should be a file +def localrefcheck(tryfn, path, lineno): + # assume it should be a file i = tryfn.find('#') if tryfn.startswith('javascript:'): return # don't check JS refs - if i != -1: + if i != -1: anchor = tryfn[i+1:] tryfn = tryfn[:i] - else: + else: anchor = '' - fn = path.dirpath(tryfn) - ishtml = fn.ext == '.html' + fn = path.dirpath(tryfn) + ishtml = fn.ext == '.html' fn = ishtml and fn.new(ext='.txt') or fn py.builtin.print_("filename is", fn) - if not fn.check(): # not ishtml or not fn.check(): - if not py.path.local(tryfn).check(): # the html could be there + if not fn.check(): # not ishtml or not fn.check(): + if not py.path.local(tryfn).check(): # the html could be there py.test.fail("reference error %r in %s:%d" %( tryfn, path.basename, lineno+1)) - if anchor: + if anchor: source = unicode(fn.read(), 'latin1') source = source.lower().replace('-', ' ') # aehem - anchor = anchor.replace('-', ' ') - match2 = ".. _`%s`:" % anchor - match3 = ".. _%s:" % anchor + anchor = anchor.replace('-', ' ') + match2 = ".. _`%s`:" % anchor + match3 = ".. _%s:" % anchor candidates = (anchor, match2, match3) py.builtin.print_("candidates", repr(candidates)) - for line in source.split('\n'): + for line in source.split('\n'): line = line.strip() - if line in candidates: - break - else: + if line in candidates: + break + else: py.test.fail("anchor reference error %s#%s in %s:%d" %( tryfn, anchor, path.basename, lineno+1)) @@ -354,20 +354,20 @@ else: pass def convert_rest_html(source, source_path, stylesheet=None, encoding='latin1'): - """ return html latin1-encoded document for the given input. + """ return html latin1-encoded document for the given input. source a ReST-string sourcepath where to look for includes (basically) stylesheet path (to be used if any) """ from docutils.core import publish_string kwargs = { - 'stylesheet' : stylesheet, + 'stylesheet' : stylesheet, 'stylesheet_path': None, - 'traceback' : 1, + 'traceback' : 1, 'embed_stylesheet': 0, - 'output_encoding' : encoding, + 'output_encoding' : encoding, #'halt' : 0, # 'info', - 'halt_level' : 2, + 'halt_level' : 2, } # docutils uses os.getcwd() :-( source_path = os.path.abspath(str(source_path)) @@ -397,9 +397,9 @@ def process(txtpath, encoding='latin1'): doc = convert_rest_html(content, txtpath, stylesheet=stylesheet, encoding=encoding) htmlpath.open('wb').write(doc) #log("wrote %r" % htmlpath) - #if txtpath.check(svnwc=1, versioned=1): + #if txtpath.check(svnwc=1, versioned=1): # info = txtpath.info() - # svninfopath.dump(info) + # svninfopath.dump(info) if sys.version_info > (3, 0): def _uni(s): return s @@ -411,16 +411,16 @@ rex1 = re.compile(r'.*(.*).*', re.MULTILINE | re.DOTALL) rex2 = re.compile(r'.*
(.*)
.*', re.MULTILINE | re.DOTALL) def strip_html_header(string, encoding='utf8'): - """ return the content of the body-tag """ + """ return the content of the body-tag """ uni = unicode(string, encoding) - for rex in rex1,rex2: - match = rex.search(uni) - if not match: - break - uni = match.group(1) - return uni + for rex in rex1,rex2: + match = rex.search(uni) + if not match: + break + uni = match.group(1) + return uni -class Project: # used for confrest.py files +class Project: # used for confrest.py files def __init__(self, sourcepath): self.sourcepath = sourcepath def process(self, path): diff --git a/py/_plugin/pytest_resultlog.py b/py/_plugin/pytest_resultlog.py index f16d5f73a..7f9292075 100644 --- a/py/_plugin/pytest_resultlog.py +++ b/py/_plugin/pytest_resultlog.py @@ -1,10 +1,10 @@ -"""non-xml machine-readable logging of test results. - Useful for buildbot integration code. See the `PyPy-test`_ - web page for post-processing. +"""non-xml machine-readable logging of test results. + Useful for buildbot integration code. See the `PyPy-test`_ + web page for post-processing. .. _`PyPy-test`: http://codespeak.net:8099/summary - -""" + +""" import py from py.builtin import print_ @@ -19,14 +19,14 @@ def pytest_configure(config): # prevent opening resultlog on slave nodes (xdist) if resultlog and not hasattr(config, 'slaveinput'): logfile = open(resultlog, 'w', 1) # line buffered - config._resultlog = ResultLog(config, logfile) + config._resultlog = ResultLog(config, logfile) config.pluginmanager.register(config._resultlog) def pytest_unconfigure(config): resultlog = getattr(config, '_resultlog', None) if resultlog: resultlog.logfile.close() - del config._resultlog + del config._resultlog config.pluginmanager.unregister(resultlog) def generic_path(item): @@ -41,7 +41,7 @@ def generic_path(item): gpath.append(':') fspart = False else: - gpath.append('.') + gpath.append('.') else: gpath.append('/') fspart = True @@ -64,7 +64,7 @@ class ResultLog(object): def log_outcome(self, node, shortrepr, longrepr): testpath = generic_path(node) - self.write_log_entry(testpath, shortrepr, longrepr) + self.write_log_entry(testpath, shortrepr, longrepr) def pytest_runtest_logreport(self, report): res = self.config.hook.pytest_report_teststatus(report=report) @@ -79,21 +79,21 @@ class ResultLog(object): elif report.passed: longrepr = "" elif report.failed: - longrepr = str(report.longrepr) + longrepr = str(report.longrepr) elif report.skipped: longrepr = str(report.longrepr.reprcrash.message) - self.log_outcome(report.item, code, longrepr) + self.log_outcome(report.item, code, longrepr) def pytest_collectreport(self, report): if not report.passed: - if report.failed: + if report.failed: code = "F" else: assert report.skipped code = "S" longrepr = str(report.longrepr.reprcrash) - self.log_outcome(report.collector, code, longrepr) + self.log_outcome(report.collector, code, longrepr) def pytest_internalerror(self, excrepr): - path = excrepr.reprcrash.path + path = excrepr.reprcrash.path self.write_log_entry(path, '!', str(excrepr)) diff --git a/py/_plugin/pytest_runner.py b/py/_plugin/pytest_runner.py index 095407e29..784c13402 100644 --- a/py/_plugin/pytest_runner.py +++ b/py/_plugin/pytest_runner.py @@ -1,23 +1,23 @@ -""" -collect and run test items and create reports. +""" +collect and run test items and create reports. """ import py, sys def pytest_namespace(): return { - 'raises' : raises, + 'raises' : raises, 'skip' : skip, 'importorskip' : importorskip, - 'fail' : fail, - 'xfail' : xfail, - 'exit' : exit, + 'fail' : fail, + 'xfail' : xfail, + 'exit' : exit, } # -# pytest plugin hooks +# pytest plugin hooks -# XXX move to pytest_sessionstart and fix py.test owns tests +# XXX move to pytest_sessionstart and fix py.test owns tests def pytest_configure(config): config._setupstate = SetupState() @@ -69,12 +69,12 @@ def pytest__teardown_final(session): ntraceback = call.excinfo.traceback .cut(excludepath=py._pydir) call.excinfo.traceback = ntraceback.filter() rep = TeardownErrorReport(call.excinfo) - return rep + return rep def pytest_report_teststatus(report): if report.when in ("setup", "teardown"): if report.failed: - # category, shortletter, verbose-word + # category, shortletter, verbose-word return "error", "E", "ERROR" elif report.skipped: return "skipped", "s", "SKIPPED" @@ -88,18 +88,18 @@ def call_and_report(item, when, log=True): hook = item.ihook report = hook.pytest_runtest_makereport(item=item, call=call) if log and (when == "call" or not report.passed): - hook.pytest_runtest_logreport(report=report) + hook.pytest_runtest_logreport(report=report) return report def call_runtest_hook(item, when): - hookname = "pytest_runtest_" + when + hookname = "pytest_runtest_" + when ihook = getattr(item.ihook, hookname) return CallInfo(lambda: ihook(item=item), when=when) class CallInfo: - excinfo = None + excinfo = None def __init__(self, func, when): - self.when = when + self.when = when try: self.result = func() except KeyboardInterrupt: @@ -134,7 +134,7 @@ class BaseReport(object): def toterminal(self, out): for line in self.headerlines: out.line(line) - longrepr = self.longrepr + longrepr = self.longrepr if hasattr(longrepr, 'toterminal'): longrepr.toterminal(out) else: @@ -143,36 +143,36 @@ class BaseReport(object): class CollectErrorRepr(BaseReport): def __init__(self, msg): super(CollectErrorRepr, self).__init__() - self.longrepr = msg + self.longrepr = msg def toterminal(self, out): out.line(str(self.longrepr), red=True) - + class ItemTestReport(BaseReport): failed = passed = skipped = False def __init__(self, item, excinfo=None, when=None): super(ItemTestReport, self).__init__() - self.item = item + self.item = item self.when = when if item and when != "setup": self.keywords = item.keywords else: - # if we fail during setup it might mean + # if we fail during setup it might mean # we are not able to access the underlying object - # this might e.g. happen if we are unpickled - # and our parent collector did not collect us + # this might e.g. happen if we are unpickled + # and our parent collector did not collect us # (because it e.g. skipped for platform reasons) - self.keywords = {} + self.keywords = {} if not excinfo: self.passed = True - self.shortrepr = "." + self.shortrepr = "." else: if not isinstance(excinfo, py.code.ExceptionInfo): self.failed = True shortrepr = "?" - longrepr = excinfo + longrepr = excinfo elif excinfo.errisinstance(py.test.skip.Exception): - self.skipped = True + self.skipped = True shortrepr = "s" longrepr = self.item._repr_failure_py(excinfo) else: @@ -180,35 +180,35 @@ class ItemTestReport(BaseReport): shortrepr = self.item.shortfailurerepr if self.when == "call": longrepr = self.item.repr_failure(excinfo) - else: # exception in setup or teardown + else: # exception in setup or teardown longrepr = self.item._repr_failure_py(excinfo) shortrepr = shortrepr.lower() - self.shortrepr = shortrepr - self.longrepr = longrepr + self.shortrepr = shortrepr + self.longrepr = longrepr def __repr__(self): - status = (self.passed and "passed" or - self.skipped and "skipped" or - self.failed and "failed" or + status = (self.passed and "passed" or + self.skipped and "skipped" or + self.failed and "failed" or "CORRUPT") l = [repr(self.item.name), "when=%r" % self.when, "outcome %r" % status,] if hasattr(self, 'node'): l.append("txnode=%s" % self.node.gateway.id) info = " " .join(map(str, l)) - return "" % info + return "" % info def getnode(self): - return self.item + return self.item class CollectReport(BaseReport): - skipped = failed = passed = False + skipped = failed = passed = False def __init__(self, collector, result, excinfo=None): super(CollectReport, self).__init__() - self.collector = collector + self.collector = collector if not excinfo: self.passed = True - self.result = result + self.result = result else: if excinfo.errisinstance(py.test.skip.Exception): self.skipped = True @@ -219,13 +219,13 @@ class CollectReport(BaseReport): errorinfo = self.collector.repr_failure(excinfo) if not hasattr(errorinfo, "toterminal"): errorinfo = CollectErrorRepr(errorinfo) - self.longrepr = errorinfo + self.longrepr = errorinfo def getnode(self): - return self.collector + return self.collector class TeardownErrorReport(BaseReport): - skipped = passed = False + skipped = passed = False failed = True when = "teardown" def __init__(self, excinfo): @@ -239,9 +239,9 @@ class SetupState(object): self._finalizers = {} def addfinalizer(self, finalizer, colitem): - """ attach a finalizer to the given colitem. - if colitem is None, this will add a finalizer that - is called at the end of teardown_all(). + """ attach a finalizer to the given colitem. + if colitem is None, this will add a finalizer that + is called at the end of teardown_all(). """ assert hasattr(finalizer, '__call__') #assert colitem in self.stack @@ -257,15 +257,15 @@ class SetupState(object): fin = finalizers.pop() fin() - def _teardown_with_finalization(self, colitem): - self._callfinalizers(colitem) - if colitem: + def _teardown_with_finalization(self, colitem): + self._callfinalizers(colitem) + if colitem: colitem.teardown() for colitem in self._finalizers: assert colitem is None or colitem in self.stack - def teardown_all(self): - while self.stack: + def teardown_all(self): + while self.stack: self._pop_and_teardown() self._teardown_with_finalization(None) assert not self._finalizers @@ -275,75 +275,75 @@ class SetupState(object): self._pop_and_teardown() else: self._callfinalizers(item) - - def prepare(self, colitem): + + def prepare(self, colitem): """ setup objects along the collector chain to the test-method and teardown previously setup objects.""" - needed_collectors = colitem.listchain() - while self.stack: - if self.stack == needed_collectors[:len(self.stack)]: - break + needed_collectors = colitem.listchain() + while self.stack: + if self.stack == needed_collectors[:len(self.stack)]: + break self._pop_and_teardown() - # check if the last collection node has raised an error + # check if the last collection node has raised an error for col in self.stack: if hasattr(col, '_prepare_exc'): - py.builtin._reraise(*col._prepare_exc) - for col in needed_collectors[len(self.stack):]: - self.stack.append(col) + py.builtin._reraise(*col._prepare_exc) + for col in needed_collectors[len(self.stack):]: + self.stack.append(col) try: - col.setup() + col.setup() except Exception: col._prepare_exc = sys.exc_info() raise # ============================================================= -# Test OutcomeExceptions and helpers for creating them. +# Test OutcomeExceptions and helpers for creating them. -class OutcomeException(Exception): - """ OutcomeException and its subclass instances indicate and - contain info about test and collection outcomes. - """ - def __init__(self, msg=None, excinfo=None): - self.msg = msg +class OutcomeException(Exception): + """ OutcomeException and its subclass instances indicate and + contain info about test and collection outcomes. + """ + def __init__(self, msg=None, excinfo=None): + self.msg = msg self.excinfo = excinfo def __repr__(self): - if self.msg: - return repr(self.msg) + if self.msg: + return repr(self.msg) return "<%s instance>" %(self.__class__.__name__,) __str__ = __repr__ -class Skipped(OutcomeException): - # XXX hackish: on 3k we fake to live in the builtins +class Skipped(OutcomeException): + # XXX hackish: on 3k we fake to live in the builtins # in order to have Skipped exception printing shorter/nicer __module__ = 'builtins' -class Failed(OutcomeException): +class Failed(OutcomeException): """ raised from an explicit call to py.test.fail() """ __module__ = 'builtins' -class XFailed(OutcomeException): +class XFailed(OutcomeException): """ raised from an explicit call to py.test.xfail() """ __module__ = 'builtins' -class ExceptionFailure(Failed): +class ExceptionFailure(Failed): """ raised by py.test.raises on an exception-assertion mismatch. """ - def __init__(self, expr, expected, msg=None, excinfo=None): - Failed.__init__(self, msg=msg, excinfo=excinfo) - self.expr = expr + def __init__(self, expr, expected, msg=None, excinfo=None): + Failed.__init__(self, msg=msg, excinfo=excinfo) + self.expr = expr self.expected = expected class Exit(KeyboardInterrupt): """ raised by py.test.exit for immediate program exits without tracebacks and reporter/summary. """ def __init__(self, msg="unknown reason"): - self.msg = msg + self.msg = msg KeyboardInterrupt.__init__(self, msg) -# exposed helper methods +# exposed helper methods -def exit(msg): - """ exit testing process as if KeyboardInterrupt was triggered. """ +def exit(msg): + """ exit testing process as if KeyboardInterrupt was triggered. """ __tracebackhide__ = True raise Exit(msg) @@ -352,23 +352,23 @@ exit.Exception = Exit def skip(msg=""): """ skip an executing test with the given message. Note: it's usually better use the py.test.mark.skipif marker to declare a test to be - skipped under certain conditions like mismatching platforms or - dependencies. See the pytest_skipping plugin for details. + skipped under certain conditions like mismatching platforms or + dependencies. See the pytest_skipping plugin for details. """ __tracebackhide__ = True - raise Skipped(msg=msg) + raise Skipped(msg=msg) skip.Exception = Skipped def fail(msg=""): """ explicitely fail an currently-executing test with the given Message. """ __tracebackhide__ = True - raise Failed(msg=msg) + raise Failed(msg=msg) fail.Exception = Failed def xfail(reason=""): - """ xfail an executing test or setup functions, taking an optional + """ xfail an executing test or setup functions, taking an optional reason string. """ __tracebackhide__ = True @@ -376,20 +376,20 @@ def xfail(reason=""): xfail.Exception = XFailed def raises(ExpectedException, *args, **kwargs): - """ assert that a code block/function call raises an exception. - - If using Python 2.5 or above, you may use this function as a + """ assert that a code block/function call raises an exception. + + If using Python 2.5 or above, you may use this function as a context manager:: >>> with raises(ZeroDivisionError): ... 1/0 - Or you can one of two forms: + Or you can one of two forms: - if args[0] is callable: raise AssertionError if calling it with - the remaining arguments does not raise the expected exception. + if args[0] is callable: raise AssertionError if calling it with + the remaining arguments does not raise the expected exception. if args[0] is a string: raise AssertionError if executing the - the string in the calling scope does not raise expected exception. + the string in the calling scope does not raise expected exception. examples: >>> x = 5 >>> raises(TypeError, lambda x: x + 'hello', x=x) @@ -423,8 +423,8 @@ def raises(ExpectedException, *args, **kwargs): if k: k = ', ' + k expr = '%s(%r%s)' %(getattr(func, '__name__', func), args, k) - raise ExceptionFailure(msg="DID NOT RAISE", - expr=args, expected=ExpectedException) + raise ExceptionFailure(msg="DID NOT RAISE", + expr=args, expected=ExpectedException) class RaisesContext(object): @@ -435,7 +435,7 @@ class RaisesContext(object): def __enter__(self): self.excinfo = object.__new__(py.code.ExceptionInfo) - return self.excinfo + return self.excinfo def __exit__(self, *tp): __tracebackhide__ = True @@ -450,9 +450,9 @@ class RaisesContext(object): raises.Exception = ExceptionFailure def importorskip(modname, minversion=None): - """ return imported module if it has a higher __version__ than the - optionally specified 'minversion' - otherwise call py.test.skip() - with a message detailing the mismatch. + """ return imported module if it has a higher __version__ than the + optionally specified 'minversion' - otherwise call py.test.skip() + with a message detailing the mismatch. """ compile(modname, '', 'eval') # to catch syntaxerrors try: diff --git a/py/_plugin/pytest_skipping.py b/py/_plugin/pytest_skipping.py index 74893c8ae..70b64aabd 100644 --- a/py/_plugin/pytest_skipping.py +++ b/py/_plugin/pytest_skipping.py @@ -1,21 +1,21 @@ """ advanced skipping for python test functions, classes or modules. -With this plugin you can mark test functions for conditional skipping +With this plugin you can mark test functions for conditional skipping or as "xfail", expected-to-fail. Skipping a test will avoid running it while xfail-marked tests will run and result in an inverted outcome: -a pass becomes a failure and a fail becomes a semi-passing one. +a pass becomes a failure and a fail becomes a semi-passing one. -The need for skipping a test is usually connected to a condition. +The need for skipping a test is usually connected to a condition. If a test fails under all conditions then it's probably better -to mark your test as 'xfail'. +to mark your test as 'xfail'. By passing ``-rxs`` to the terminal reporter you will see extra -summary information on skips and xfail-run tests at the end of a test run. +summary information on skips and xfail-run tests at the end of a test run. .. _skipif: -Skipping a single function +Skipping a single function ------------------------------------------- Here is an example for marking a test function to be skipped @@ -25,17 +25,17 @@ when run on a Python3 interpreter:: def test_function(): ... -During test function setup the skipif condition is +During test function setup the skipif condition is evaluated by calling ``eval(expr, namespace)``. The namespace -contains the ``sys`` and ``os`` modules and the test -``config`` object. The latter allows you to skip based +contains the ``sys`` and ``os`` modules and the test +``config`` object. The latter allows you to skip based on a test configuration value e.g. like this:: @py.test.mark.skipif("not config.getvalue('db')") def test_function(...): ... -Create a shortcut for your conditional skip decorator +Create a shortcut for your conditional skip decorator at module level like this:: win32only = py.test.mark.skipif("sys.platform != 'win32'") @@ -45,34 +45,34 @@ at module level like this:: ... -skip groups of test functions +skip groups of test functions -------------------------------------- As with all metadata function marking you can do it at -`whole class- or module level`_. Here is an example +`whole class- or module level`_. Here is an example for skipping all methods of a test class based on platform:: class TestPosixCalls: pytestmark = py.test.mark.skipif("sys.platform == 'win32'") - + def test_function(self): # will not be setup or run under 'win32' platform # The ``pytestmark`` decorator will be applied to each test function. -If your code targets python2.6 or above you can equivalently use +If your code targets python2.6 or above you can equivalently use the skipif decorator on classes:: @py.test.mark.skipif("sys.platform == 'win32'") class TestPosixCalls: - + def test_function(self): # will not be setup or run under 'win32' platform # It is fine in general to apply multiple "skipif" decorators on a single function - this means that if any of the conditions -apply the function will be skipped. +apply the function will be skipped. .. _`whole class- or module level`: mark.html#scoped-marking @@ -82,7 +82,7 @@ mark a test function as **expected to fail** ------------------------------------------------------- You can use the ``xfail`` marker to indicate that you -expect the test to fail:: +expect the test to fail:: @py.test.mark.xfail def test_function(): @@ -111,7 +111,7 @@ imperative xfail from within a test or setup function ------------------------------------------------------ If you cannot declare xfail-conditions at import time -you can also imperatively produce an XFail-outcome from +you can also imperatively produce an XFail-outcome from within test or setup code. Example:: def test_function(): @@ -122,7 +122,7 @@ within test or setup code. Example:: skipping on a missing import dependency -------------------------------------------------- -You can use the following import helper at module level +You can use the following import helper at module level or within a test or test setup function:: docutils = py.test.importorskip("docutils") @@ -139,7 +139,7 @@ imperative skip from within a test or setup function ------------------------------------------------------ If for some reason you cannot declare skip-conditions -you can also imperatively produce a Skip-outcome from +you can also imperatively produce a Skip-outcome from within test or setup code. Example:: def test_function(): @@ -152,7 +152,7 @@ import py def pytest_addoption(parser): group = parser.getgroup("general") - group.addoption('--runxfail', + group.addoption('--runxfail', action="store_true", dest="runxfail", default=False, help="run tests even if they are marked xfail") @@ -198,7 +198,7 @@ class MarkEvaluator: else: return "condition: " + self.expr return expl - + def pytest_runtest_setup(item): if not isinstance(item, py.test.collect.Function): @@ -222,7 +222,7 @@ def check_xfail_no_run(item): def pytest_runtest_makereport(__multicall__, item, call): if not isinstance(item, py.test.collect.Function): return - if not (call.excinfo and + if not (call.excinfo and call.excinfo.errisinstance(py.test.xfail.Exception)): evalxfail = getattr(item, '_evalxfail', None) if not evalxfail: @@ -323,13 +323,13 @@ def cached_eval(config, expr, d): def folded_skips(skipped): d = {} for event in skipped: - entry = event.longrepr.reprcrash + entry = event.longrepr.reprcrash key = entry.path, entry.lineno, entry.message d.setdefault(key, []).append(event) l = [] - for key, events in d.items(): + for key, events in d.items(): l.append((len(events),) + key) - return l + return l def show_skipped(terminalreporter, lines): tr = terminalreporter diff --git a/py/_plugin/pytest_terminal.py b/py/_plugin/pytest_terminal.py index 4b06f786a..be3d21e5f 100644 --- a/py/_plugin/pytest_terminal.py +++ b/py/_plugin/pytest_terminal.py @@ -1,14 +1,14 @@ """ Implements terminal reporting of the full testing process. -This is a good source for looking at the various reporting hooks. +This is a good source for looking at the various reporting hooks. """ import py import sys def pytest_addoption(parser): group = parser.getgroup("terminal reporting", "reporting", after="general") - group._addoption('-v', '--verbose', action="count", + group._addoption('-v', '--verbose', action="count", dest="verbose", default=0, help="increase verbosity."), group._addoption('-r', action="store", dest="reportchars", default=None, metavar="chars", @@ -20,7 +20,7 @@ def pytest_addoption(parser): group._addoption('--report', action="store", dest="report", default=None, metavar="opts", help="(deprecated, use -r)") - group._addoption('--tb', metavar="style", + group._addoption('--tb', metavar="style", action="store", dest="tbstyle", default='long', type="choice", choices=['long', 'short', 'no', 'line'], help="traceback print mode (long/short/line/no).") @@ -40,7 +40,7 @@ def pytest_configure(config): else: reporter = TerminalReporter(config) if reporter: - # XXX see remote.py's XXX + # XXX see remote.py's XXX for attr in 'pytest_terminal_hasmarkup', 'pytest_terminal_fullwidth': if hasattr(config, attr): #print "SETTING TERMINAL OPTIONS", attr, getattr(config, attr) @@ -53,7 +53,7 @@ def getreportopt(config): reportopts = "" optvalue = config.getvalue("report") if optvalue: - py.builtin.print_("DEPRECATED: use -r instead of --report option.", + py.builtin.print_("DEPRECATED: use -r instead of --report option.", file=py.std.sys.stderr) if optvalue: for setting in optvalue.split(","): @@ -71,13 +71,13 @@ def getreportopt(config): class TerminalReporter: def __init__(self, config, file=None): - self.config = config - self.stats = {} + self.config = config + self.stats = {} self.curdir = py.path.local() if file is None: file = py.std.sys.stdout self._tw = py.io.TerminalWriter(file) - self.currentfspath = None + self.currentfspath = None self.reportchars = getreportopt(config) def hasopt(self, char): @@ -96,14 +96,14 @@ class TerminalReporter: def write_ensure_prefix(self, prefix, extra="", **kwargs): if self.currentfspath != prefix: self._tw.line() - self.currentfspath = prefix + self.currentfspath = prefix self._tw.write(prefix) if extra: self._tw.write(extra, **kwargs) self.currentfspath = -2 def ensure_newline(self): - if self.currentfspath: + if self.currentfspath: self._tw.line() self.currentfspath = None @@ -122,20 +122,20 @@ class TerminalReporter: return res for cat in 'skipped failed passed ???'.split(): if getattr(rep, cat, None): - break + break return cat, self.getoutcomeletter(rep), self.getoutcomeword(rep) def getoutcomeletter(self, rep): - return rep.shortrepr + return rep.shortrepr def getoutcomeword(self, rep): - if rep.passed: + if rep.passed: return "PASS", dict(green=True) - elif rep.failed: + elif rep.failed: return "FAIL", dict(red=True) - elif rep.skipped: + elif rep.skipped: return "SKIP" - else: + else: return "???", dict(red=True) def gettestid(self, item, relative=True): @@ -157,11 +157,11 @@ class TerminalReporter: self.write_line("INTERNALERROR> " + line) def pytest_plugin_registered(self, plugin): - if self.config.option.traceconfig: + if self.config.option.traceconfig: msg = "PLUGIN registered: %s" %(plugin,) - # XXX this event may happen during setup/teardown time - # which unfortunately captures our output here - # which garbles our output if we use self.write_line + # XXX this event may happen during setup/teardown time + # which unfortunately captures our output here + # which garbles our output if we use self.write_line self.write_line(msg) def pytest_trace(self, category, msg): @@ -175,15 +175,15 @@ class TerminalReporter: def pytest_itemstart(self, item, node=None): if self.config.option.verbose: line = self._reportinfoline(item) - self.write_ensure_prefix(line, "") + self.write_ensure_prefix(line, "") else: - # ensure that the path is printed before the + # ensure that the path is printed before the # 1st test of a module starts running self.write_fspath_result(self._getfspath(item), "") def pytest__teardown_final_logerror(self, report): self.stats.setdefault("error", []).append(report) - + def pytest_runtest_logreport(self, report): rep = report cat, letter, word = self.getcategoryletterword(rep) @@ -236,7 +236,7 @@ class TerminalReporter: self.write_line("test path %d: %s" %(i+1, testarg)) def pytest_sessionfinish(self, exitstatus, __multicall__): - __multicall__.execute() + __multicall__.execute() self._tw.line("") if exitstatus in (0, 1, 2): self.summary_errors() @@ -280,7 +280,7 @@ class TerminalReporter: else: line = "[noreportinfo]" return line % locals() + " " - + def _getfailureheadline(self, rep): if hasattr(rep, "collector"): return str(rep.collector.fspath) @@ -288,7 +288,7 @@ class TerminalReporter: fspath, lineno, msg = self._getreportinfo(rep.item) return msg else: - return "test session" + return "test session" def _getreportinfo(self, item): try: @@ -308,7 +308,7 @@ class TerminalReporter: return fspath # - # summaries for sessionfinish + # summaries for sessionfinish # def summary_failures(self): @@ -319,7 +319,7 @@ class TerminalReporter: if tbstyle == "line": line = rep._getcrashline() self.write_line(line) - else: + else: msg = self._getfailureheadline(rep) self.write_sep("_", msg) rep.toterminal(self._tw) @@ -333,9 +333,9 @@ class TerminalReporter: # collect msg = "ERROR collecting " + msg elif rep.when == "setup": - msg = "ERROR at setup of " + msg + msg = "ERROR at setup of " + msg elif rep.when == "teardown": - msg = "ERROR at teardown of " + msg + msg = "ERROR at teardown of " + msg self.write_sep("_", msg) rep.toterminal(self._tw) @@ -365,7 +365,7 @@ class CollectonlyReporter: INDENT = " " def __init__(self, config, out=None): - self.config = config + self.config = config if out is None: out = py.std.sys.stdout self._tw = py.io.TerminalWriter(out) @@ -381,8 +381,8 @@ class CollectonlyReporter: def pytest_collectstart(self, collector): self.outindent(collector) - self.indent += self.INDENT - + self.indent += self.INDENT + def pytest_itemstart(self, item, node=None): self.outindent(item) @@ -397,7 +397,7 @@ class CollectonlyReporter: self._tw.sep("!", "collection failures") for rep in self._failed: rep.toterminal(self._tw) - + def repr_pythonversion(v=None): if v is None: @@ -437,7 +437,7 @@ class ShowFuncargSession(Session): if name.startswith(FuncargRequest._argprefix): name = name[len(FuncargRequest._argprefix):] if name not in available: - available.append([name, factory]) + available.append([name, factory]) if available: pluginname = plugin.__name__ for name, factory in available: @@ -452,7 +452,7 @@ class ShowFuncargSession(Session): for line in doc.split("\n"): tw.line(" " + line.strip()) else: - tw.line(" %s: no docstring available" %(loc,), + tw.line(" %s: no docstring available" %(loc,), red=True) def getlocation(self, function): diff --git a/py/_plugin/pytest_tmpdir.py b/py/_plugin/pytest_tmpdir.py index 4c105cb42..83907c7a6 100644 --- a/py/_plugin/pytest_tmpdir.py +++ b/py/_plugin/pytest_tmpdir.py @@ -1,4 +1,4 @@ -"""provide temporary directories to test functions. +"""provide temporary directories to test functions. usage example:: @@ -15,8 +15,8 @@ def pytest_funcarg__tmpdir(request): unique to each test function invocation, created as a sub directory of the base temporary directory. The returned object is a `py.path.local`_ - path object. + path object. """ - name = request.function.__name__ + name = request.function.__name__ x = request.config.mktemp(name, numbered=True) return x.realpath() diff --git a/py/_plugin/pytest_unittest.py b/py/_plugin/pytest_unittest.py index 54209d0d9..a6a2a31c0 100644 --- a/py/_plugin/pytest_unittest.py +++ b/py/_plugin/pytest_unittest.py @@ -1,15 +1,15 @@ """ -automatically discover and run traditional "unittest.py" style tests. +automatically discover and run traditional "unittest.py" style tests. Usage ---------------- -This plugin collects and runs Python `unittest.py style`_ tests. -It will automatically collect ``unittest.TestCase`` subclasses +This plugin collects and runs Python `unittest.py style`_ tests. +It will automatically collect ``unittest.TestCase`` subclasses and their ``test`` methods from the test modules of a project -(usually following the ``test_*.py`` pattern). +(usually following the ``test_*.py`` pattern). -This plugin is enabled by default. +This plugin is enabled by default. .. _`unittest.py style`: http://docs.python.org/library/unittest.html """ @@ -54,7 +54,7 @@ class UnitTestCaseInstance(py.test.collect.Instance): def _getobj(self): x = self.parent.obj return self.parent.obj(methodName='run') - + class UnitTestFunction(py.test.collect.Function): def __init__(self, name, parent, args=(), obj=_dummy, sort_value=None): super(UnitTestFunction, self).__init__(name, parent) diff --git a/py/_plugin/standalonetemplate.py b/py/_plugin/standalonetemplate.py index 2d238b578..a41f7ca4d 100755 --- a/py/_plugin/standalonetemplate.py +++ b/py/_plugin/standalonetemplate.py @@ -28,14 +28,14 @@ class DictImporter(object): except KeyError: s = self.sources[fullname+'.__init__'] is_pkg = True - + co = compile(s, fullname, 'exec') module = sys.modules.setdefault(fullname, ModuleType(fullname)) module.__file__ = "%s/%s" % (__file__, fullname) module.__loader__ = self if is_pkg: module.__path__ = [fullname] - + do_exec(co, module.__dict__) return sys.modules[fullname] @@ -49,7 +49,7 @@ if __name__ == "__main__": if sys.version_info >= (3,0): exec("def do_exec(co, loc): exec(co, loc)\n") import pickle - sources = sources.encode("ascii") # ensure bytes + sources = sources.encode("ascii") # ensure bytes sources = pickle.loads(zlib.decompress(base64.decodebytes(sources))) else: import cPickle as pickle diff --git a/py/_process/cmdexec.py b/py/_process/cmdexec.py index 43c71629c..4ceb647a9 100644 --- a/py/_process/cmdexec.py +++ b/py/_process/cmdexec.py @@ -16,11 +16,11 @@ def cmdexec(cmd): if the subprocess module does not provide a proper encoding/unicode strings sys.getdefaultencoding() will be used, if that does not exist, 'UTF-8'. """ - process = subprocess.Popen(cmd, shell=True, + process = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = process.communicate() - if sys.version_info[0] < 3: # on py3 we get unicode strings, on py2 not + if sys.version_info[0] < 3: # on py3 we get unicode strings, on py2 not try: default_encoding = sys.getdefaultencoding() # jython may not have it except AttributeError: diff --git a/py/_process/forkedfunc.py b/py/_process/forkedfunc.py index c8b650246..604412c2e 100644 --- a/py/_process/forkedfunc.py +++ b/py/_process/forkedfunc.py @@ -1,10 +1,10 @@ -""" +""" ForkedFunc provides a way to run a function in a forked process and get at its return value, stdout and stderr output as well - as signals and exitstatusus. + as signals and exitstatusus. - XXX see if tempdir handling is sane + XXX see if tempdir handling is sane """ import py @@ -29,8 +29,8 @@ class ForkedFunc(object): pid = os.fork() if pid: # in parent process - self.pid = pid - else: # in child process + self.pid = pid + else: # in child process self._child(nice_level) def _child(self, nice_level): @@ -65,7 +65,7 @@ class ForkedFunc(object): os.close(1) os.close(2) os._exit(EXITSTATUS) - + def waitfinish(self, waiter=os.waitpid): pid, systemstatus = waiter(self.pid, 0) if systemstatus: diff --git a/py/_process/killproc.py b/py/_process/killproc.py index 8fa628cbd..18e8310b5 100644 --- a/py/_process/killproc.py +++ b/py/_process/killproc.py @@ -7,7 +7,7 @@ if sys.platform == "win32" or getattr(os, '_name', '') == 'nt': except ImportError: def dokill(pid): py.process.cmdexec("taskkill /F /PID %d" %(pid,)) - else: + else: def dokill(pid): PROCESS_TERMINATE = 1 handle = ctypes.windll.kernel32.OpenProcess( @@ -16,7 +16,7 @@ if sys.platform == "win32" or getattr(os, '_name', '') == 'nt': ctypes.windll.kernel32.CloseHandle(handle) else: def dokill(pid): - os.kill(pid, 15) + os.kill(pid, 15) def kill(pid): """ kill process by id. """ diff --git a/py/_std.py b/py/_std.py index bca23ea2d..97a985332 100644 --- a/py/_std.py +++ b/py/_std.py @@ -1,9 +1,9 @@ import sys class Std(object): - """ makes top-level python modules available as an attribute, - importing them on first access. - """ + """ makes top-level python modules available as an attribute, + importing them on first access. + """ def __init__(self): self.__dict__ = sys.modules diff --git a/py/_test/cmdline.py b/py/_test/cmdline.py index 80ca99d4f..10f13f795 100644 --- a/py/_test/cmdline.py +++ b/py/_test/cmdline.py @@ -10,7 +10,7 @@ def main(args=None): args = sys.argv[1:] config = py.test.config try: - config.parse(args) + config.parse(args) config.pluginmanager.do_configure(config) session = config.initsession() colitems = config.getinitialnodes() diff --git a/py/_test/collect.py b/py/_test/collect.py index b61ae741e..4e59eb59d 100644 --- a/py/_test/collect.py +++ b/py/_test/collect.py @@ -1,6 +1,6 @@ """ test collection nodes, forming a tree, Items are leafs. -""" +""" import py def configproperty(name): @@ -21,25 +21,25 @@ class HookProxy: return hookmethod.pcall(plugins, **kwargs) return call_matching_hooks -class Node(object): - """ base class for all Nodes in the collection tree. - Collector subclasses have children, Items are terminal nodes. +class Node(object): + """ base class for all Nodes in the collection tree. + Collector subclasses have children, Items are terminal nodes. """ def __init__(self, name, parent=None, config=None): - self.name = name + self.name = name self.parent = parent self.config = config or parent.config - self.fspath = getattr(parent, 'fspath', None) + self.fspath = getattr(parent, 'fspath', None) self.ihook = HookProxy(self) self.keywords = self.readkeywords() def _reraiseunpicklingproblem(self): if hasattr(self, '_unpickle_exc'): py.builtin._reraise(*self._unpickle_exc) - - # + + # # note to myself: Pickling is uh. - # + # def __getstate__(self): return (self.name, self.parent) def __setstate__(self, nameparent): @@ -49,7 +49,7 @@ class Node(object): for colitem in colitems: if colitem.name == name: # we are a copy that will not be returned - # by our parent + # by our parent self.__dict__ = colitem.__dict__ break else: @@ -60,41 +60,41 @@ class Node(object): except Exception: # our parent can't collect us but we want unpickling to # otherwise continue - self._reraiseunpicklingproblem() will - # reraise the problem + # reraise the problem self._unpickle_exc = py.std.sys.exc_info() - self.name = name - self.parent = parent + self.name = name + self.parent = parent self.config = parent.config - def __repr__(self): + def __repr__(self): if getattr(self.config.option, 'debug', False): - return "<%s %r %0x>" %(self.__class__.__name__, + return "<%s %r %0x>" %(self.__class__.__name__, getattr(self, 'name', None), id(self)) else: - return "<%s %r>" %(self.__class__.__name__, + return "<%s %r>" %(self.__class__.__name__, getattr(self, 'name', None)) # methods for ordering nodes - def __eq__(self, other): + def __eq__(self, other): if not isinstance(other, Node): - return False - return self.name == other.name and self.parent == other.parent + return False + return self.name == other.name and self.parent == other.parent def __ne__(self, other): return not self == other - + def __hash__(self): return hash((self.name, self.parent)) - - def setup(self): + + def setup(self): pass - def teardown(self): + def teardown(self): pass def _memoizedcall(self, attrname, function): - exattrname = "_ex_" + attrname + exattrname = "_ex_" + attrname failure = getattr(self, exattrname, None) if failure is not None: py.builtin._reraise(failure[0], failure[1], failure[2]) @@ -109,37 +109,37 @@ class Node(object): setattr(self, exattrname, failure) raise setattr(self, attrname, res) - return res + return res def listchain(self): - """ return list of all parent collectors up to self, - starting from root of collection tree. """ + """ return list of all parent collectors up to self, + starting from root of collection tree. """ l = [self] - while 1: + while 1: x = l[0] if x.parent is not None and x.parent.parent is not None: l.insert(0, x.parent) - else: - return l + else: + return l - def listnames(self): + def listnames(self): return [x.name for x in self.listchain()] def getparent(self, cls): current = self while current and not isinstance(current, cls): current = current.parent - return current - + return current + def readkeywords(self): return dict([(x, True) for x in self._keywords()]) def _keywords(self): return [self.name] - def _skipbykeyword(self, keywordexpr): - """ return True if they given keyword expression means to - skip this collector/item. + def _skipbykeyword(self, keywordexpr): + """ return True if they given keyword expression means to + skip this collector/item. """ if not keywordexpr: return @@ -171,7 +171,7 @@ class Node(object): return False def _prunetraceback(self, traceback): - return traceback + return traceback def _repr_failure_py(self, excinfo, style=None): if self.config.option.fulltrace: @@ -179,13 +179,13 @@ class Node(object): else: excinfo.traceback = self._prunetraceback(excinfo.traceback) # XXX should excinfo.getrepr record all data and toterminal() - # process it? + # process it? if style is None: if self.config.option.tbstyle == "short": style = "short" else: style = "long" - return excinfo.getrepr(funcargs=True, + return excinfo.getrepr(funcargs=True, showlocals=self.config.option.showlocals, style=style) @@ -193,7 +193,7 @@ class Node(object): shortfailurerepr = "F" class Collector(Node): - """ + """ Collector instances create children through collect() and thus iteratively build a tree. attributes:: @@ -207,8 +207,8 @@ class Collector(Node): """ an error during collection, contains a custom message. """ def collect(self): - """ returns a list of children (items and collectors) - for this collection node. + """ returns a list of children (items and collectors) + for this collection node. """ raise NotImplementedError("abstract") @@ -230,9 +230,9 @@ class Collector(Node): return self._memoizedcall('_collected', self.collect) # ********************************************************************** - # DEPRECATED METHODS + # DEPRECATED METHODS # ********************************************************************** - + def _deprecated_collect(self): # avoid recursion: # collect -> _deprecated_collect -> custom run() -> @@ -250,30 +250,30 @@ class Collector(Node): def run(self): """ DEPRECATED: returns a list of names available from this collector. You can return an empty list. Callers of this method - must take care to catch exceptions properly. + must take care to catch exceptions properly. """ return [colitem.name for colitem in self._memocollect()] - def join(self, name): - """ DEPRECATED: return a child collector or item for the given name. - If the return value is None there is no such child. + def join(self, name): + """ DEPRECATED: return a child collector or item for the given name. + If the return value is None there is no such child. """ return self.collect_by_name(name) def _prunetraceback(self, traceback): if hasattr(self, 'fspath'): - path = self.fspath + path = self.fspath ntraceback = traceback.cut(path=self.fspath) if ntraceback == traceback: ntraceback = ntraceback.cut(excludepath=py._pydir) traceback = ntraceback.filter() - return traceback + return traceback -class FSCollector(Collector): +class FSCollector(Collector): def __init__(self, fspath, parent=None, config=None): - fspath = py.path.local(fspath) + fspath = py.path.local(fspath) super(FSCollector, self).__init__(fspath.basename, parent, config=config) - self.fspath = fspath + self.fspath = fspath def __getstate__(self): # RootCollector.getbynames() inserts a directory which we need @@ -286,17 +286,17 @@ class FSCollector(Collector): class File(FSCollector): """ base class for collecting tests from a file. """ -class Directory(FSCollector): - def recfilter(self, path): +class Directory(FSCollector): + def recfilter(self, path): if path.check(dir=1, dotfile=0): return path.basename not in ('CVS', '_darcs', '{arch}') def collect(self): - l = self._deprecated_collect() + l = self._deprecated_collect() if l is not None: - return l + return l l = [] - for path in self.fspath.listdir(sort=True): + for path in self.fspath.listdir(sort=True): res = self.consider(path) if res is not None: if isinstance(res, (list, tuple)): @@ -322,7 +322,7 @@ class Directory(FSCollector): assert x.parent == self, (x.parent, self) assert x.fspath == path, (x.fspath, path) l.append(x) - res = l + res = l return res def consider_file(self, path): @@ -333,7 +333,7 @@ class Directory(FSCollector): py.log._apiwarn("0.99", "usefilters argument not needed") return self.ihook.pytest_collect_directory(path=path, parent=self) -class Item(Node): +class Item(Node): """ a basic test item. """ def _deprecated_testexecution(self): if self.__class__.run != Item.run: @@ -355,21 +355,21 @@ class Item(Node): def reportinfo(self): return self.fspath, None, "" - + def warnoldcollect(function=None): - py.log._apiwarn("1.0", + py.log._apiwarn("1.0", "implement collector.collect() instead of " "collector.run() and collector.join()", stacklevel=2, function=function) def warnoldtestrun(function=None): - py.log._apiwarn("1.0", + py.log._apiwarn("1.0", "implement item.runtest() instead of " "item.run() and item.execute()", stacklevel=2, function=function) - + class RootCollector(Directory): def __init__(self, config): Directory.__init__(self, config.topdir, parent=None, config=config) @@ -377,13 +377,13 @@ class RootCollector(Directory): def __repr__(self): return "" %(self.fspath,) - + def getbynames(self, names): current = self.consider(self.config.topdir) while names: name = names.pop(0) if name == ".": # special "identity" name - continue + continue l = [] for x in current._memocollect(): if x.name == name: @@ -401,7 +401,7 @@ class RootCollector(Directory): def totrail(self, node): chain = node.listchain() - names = [self._getrelpath(chain[0].fspath)] + names = [self._getrelpath(chain[0].fspath)] names += [x.name for x in chain[1:]] return names @@ -415,7 +415,7 @@ class RootCollector(Directory): if fspath == topdir: relpath = "." else: - raise ValueError("%r not relative to topdir %s" + raise ValueError("%r not relative to topdir %s" %(self.fspath, topdir)) return relpath diff --git a/py/_test/config.py b/py/_test/config.py index 03e27ece5..d72ddb722 100644 --- a/py/_test/config.py +++ b/py/_test/config.py @@ -4,16 +4,16 @@ from py._test.pluginmanager import PluginManager from py._test import parseopt from py._test.collect import RootCollector -def ensuretemp(string, dir=1): +def ensuretemp(string, dir=1): """ (deprecated) return temporary directory path with - the given string as the trailing part. It is usually + the given string as the trailing part. It is usually better to use the 'tmpdir' function argument which will - take care to provide empty unique directories for each - test call even if the test is called multiple times. - """ + take care to provide empty unique directories for each + test call even if the test is called multiple times. + """ #py.log._apiwarn(">1.1", "use tmpdir function argument") return py.test.config.ensuretemp(string, dir=dir) - + class CmdOptions(object): """ holds cmdline options as attributes.""" def __init__(self, **kwargs): @@ -24,14 +24,14 @@ class CmdOptions(object): class Error(Exception): """ Test Configuration Error. """ -class Config(object): +class Config(object): """ access to config values, pluginmanager and plugin hooks. """ - Option = py.std.optparse.Option + Option = py.std.optparse.Option Error = Error basetemp = None _sessionclass = None - def __init__(self, topdir=None, option=None): + def __init__(self, topdir=None, option=None): self.option = option or CmdOptions() self.topdir = topdir self._parser = parseopt.Parser( @@ -48,7 +48,7 @@ class Config(object): def _getmatchingplugins(self, fspath): allconftests = self._conftest._conftestpath2mod.values() - plugins = [x for x in self.pluginmanager.getplugins() + plugins = [x for x in self.pluginmanager.getplugins() if x not in allconftests] plugins += self._conftest.getconftestmodules(fspath) return plugins @@ -69,7 +69,7 @@ class Config(object): val = float(val) elif not opt.type and opt.action in ("store_true", "store_false"): val = eval(val) - opt.default = val + opt.default = val else: name = "option_" + opt.dest try: @@ -83,13 +83,13 @@ class Config(object): self.pluginmanager.consider_setuptools_entrypoints() self.pluginmanager.consider_env() self.pluginmanager.consider_preparse(args) - self._conftest.setinitial(args) + self._conftest.setinitial(args) self.pluginmanager.do_addoption(self._parser) - def parse(self, args): - """ parse cmdline arguments into this config object. - Note that this can only be called once per testing process. - """ + def parse(self, args): + """ parse cmdline arguments into this config object. + Note that this can only be called once per testing process. + """ assert not hasattr(self, 'args'), ( "can only parse cmdline args at most once per Config object") self._preparse(args) @@ -106,25 +106,25 @@ class Config(object): self._argfspaths = [py.path.local(decodearg(x)[0]) for x in args] # config objects are usually pickled across system - # barriers but they contain filesystem paths. + # barriers but they contain filesystem paths. # upon getstate/setstate we take care to do everything - # relative to "topdir". + # relative to "topdir". def __getstate__(self): l = [] for path in self.args: path = py.path.local(path) - l.append(path.relto(self.topdir)) + l.append(path.relto(self.topdir)) return l, self.option.__dict__ def __setstate__(self, repr): - # we have to set py.test.config because loading - # of conftest files may use it (deprecated) - # mainly by py.test.config.addoptions() + # we have to set py.test.config because loading + # of conftest files may use it (deprecated) + # mainly by py.test.config.addoptions() global config_per_process - py.test.config = config_per_process = self - args, cmdlineopts = repr + py.test.config = config_per_process = self + args, cmdlineopts = repr cmdlineopts = CmdOptions(**cmdlineopts) - # next line will registers default plugins + # next line will registers default plugins self.__init__(topdir=py.path.local(), option=cmdlineopts) self._rootcol = RootCollector(config=self) args = [str(self.topdir.join(x)) for x in args] @@ -132,11 +132,11 @@ class Config(object): self._setargs(args) def ensuretemp(self, string, dir=True): - return self.getbasetemp().ensure(string, dir=dir) + return self.getbasetemp().ensure(string, dir=dir) def getbasetemp(self): if self.basetemp is None: - basetemp = self.option.basetemp + basetemp = self.option.basetemp if basetemp: basetemp = py.path.local(basetemp) if not basetemp.check(dir=1): @@ -144,7 +144,7 @@ class Config(object): else: basetemp = py.path.local.make_numbered_dir(prefix='pytest-') self.basetemp = basetemp - return self.basetemp + return self.basetemp def mktemp(self, basename, numbered=False): basetemp = self.getbasetemp() @@ -188,7 +188,7 @@ class Config(object): def getconftest_pathlist(self, name, path=None): """ return a matching value, which needs to be sequence of filenames that will be returned as a list of Path - objects (they can be relative to the location + objects (they can be relative to the location where they were found). """ try: @@ -202,22 +202,22 @@ class Config(object): relroot = relroot.replace("/", py.path.local.sep) relroot = modpath.join(relroot, abs=True) l.append(relroot) - return l - - def addoptions(self, groupname, *specs): - """ add a named group of options to the current testing session. - This function gets invoked during testing session initialization. - """ + return l + + def addoptions(self, groupname, *specs): + """ add a named group of options to the current testing session. + This function gets invoked during testing session initialization. + """ py.log._apiwarn("1.0", "define pytest_addoptions(parser) to add options", stacklevel=2) group = self._parser.getgroup(groupname) for opt in specs: group._addoption_instance(opt) - return self.option + return self.option def addoption(self, *optnames, **attrs): return self._parser.addoption(*optnames, **attrs) - def getvalueorskip(self, name, path=None): + def getvalueorskip(self, name, path=None): """ return getvalue() or call py.test.skip if no value exists. """ try: val = self.getvalue(name, path) @@ -227,12 +227,12 @@ class Config(object): except KeyError: py.test.skip("no %r value found" %(name,)) - def getvalue(self, name, path=None): + def getvalue(self, name, path=None): """ return 'name' value looked up from the 'options' - and then from the first conftest file found up - the path (including the path itself). + and then from the first conftest file found up + the path (including the path itself). if path is None, lookup the value in the initial - conftest modules found during command line parsing. + conftest modules found during command line parsing. """ try: return getattr(self.option, name) @@ -247,7 +247,7 @@ class Config(object): def initsession(self): """ return an initialized session object. """ - cls = self._sessionclass + cls = self._sessionclass if cls is None: from py._test.session import Session cls = Session @@ -259,10 +259,10 @@ class Config(object): # helpers # -def gettopdir(args): +def gettopdir(args): """ return the top directory for the given paths. - if the common base dir resides in a python package - parent directory of the root package is returned. + if the common base dir resides in a python package + parent directory of the root package is returned. """ fsargs = [py.path.local(decodearg(arg)[0]) for arg in args] p = fsargs and fsargs[0] or None @@ -282,10 +282,10 @@ def decodearg(arg): return arg.split("::") def onpytestaccess(): - # it's enough to have our containing module loaded as + # it's enough to have our containing module loaded as # it initializes a per-process config instance # which loads default plugins which add to py.test.* - pass + pass -# a default per-process instance of py.test configuration +# a default per-process instance of py.test configuration config_per_process = Config() diff --git a/py/_test/conftesthandle.py b/py/_test/conftesthandle.py index 9461e01ed..5637565ea 100644 --- a/py/_test/conftesthandle.py +++ b/py/_test/conftesthandle.py @@ -1,13 +1,13 @@ import py class Conftest(object): - """ the single place for accessing values and interacting - towards conftest modules from py.test objects. + """ the single place for accessing values and interacting + towards conftest modules from py.test objects. (deprecated) - Note that triggering Conftest instances to import - conftest.py files may result in added cmdline options. - """ + Note that triggering Conftest instances to import + conftest.py files may result in added cmdline options. + """ def __init__(self, onimport=None, confcutdir=None): self._path2confmods = {} self._onimport = onimport @@ -16,12 +16,12 @@ class Conftest(object): def setinitial(self, args): """ try to find a first anchor path for looking up global values - from conftests. This function is usually called _before_ + from conftests. This function is usually called _before_ argument parsing. conftest files may add command line options and we thus have no completely safe way of determining which parts of the arguments are actually related to options - and which are file system paths. We just try here to get - bootstrapped ... + and which are file system paths. We just try here to get + bootstrapped ... """ current = py.path.local() opt = '--confcutdir' @@ -33,15 +33,15 @@ class Conftest(object): p = current.join(args[i+1], abs=True) elif opt1.startswith(opt + "="): p = current.join(opt1[len(opt)+1:], abs=1) - self._confcutdir = p + self._confcutdir = p break for arg in args + [current]: if hasattr(arg, 'startswith') and arg.startswith("--"): continue anchor = current.join(arg, abs=1) - if anchor.check(): # we found some file object + if anchor.check(): # we found some file object self._path2confmods[None] = self.getconftestmodules(anchor) - # let's also consider test* dirs + # let's also consider test* dirs if anchor.check(dir=1): for x in anchor.listdir(lambda x: x.check(dir=1, dotfile=0)): self.getconftestmodules(x) @@ -50,7 +50,7 @@ class Conftest(object): assert 0, "no root of filesystem?" def getconftestmodules(self, path): - """ return a list of imported conftest modules for the given path. """ + """ return a list of imported conftest modules for the given path. """ try: clist = self._path2confmods[path] except KeyError: @@ -70,7 +70,7 @@ class Conftest(object): clist.append(self.importconftest(conftestpath)) self._path2confmods[path] = clist # be defensive: avoid changes from caller side to - # affect us by always returning a copy of the actual list + # affect us by always returning a copy of the actual list return clist[:] def rget(self, name, path=None): @@ -92,9 +92,9 @@ class Conftest(object): try: return self._conftestpath2mod[conftestpath] except KeyError: - if not conftestpath.dirpath('__init__.py').check(file=1): - # HACK: we don't want any "globally" imported conftest.py, - # prone to conflicts and subtle problems + if not conftestpath.dirpath('__init__.py').check(file=1): + # HACK: we don't want any "globally" imported conftest.py, + # prone to conflicts and subtle problems modname = str(conftestpath).replace('.', conftestpath.sep) mod = conftestpath.pyimport(modname=modname) else: diff --git a/py/_test/funcargs.py b/py/_test/funcargs.py index 7caf01529..5d69b1939 100644 --- a/py/_test/funcargs.py +++ b/py/_test/funcargs.py @@ -3,15 +3,15 @@ import py def getfuncargnames(function): argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0] startindex = py.std.inspect.ismethod(function) and 1 or 0 - defaults = getattr(function, 'func_defaults', + defaults = getattr(function, 'func_defaults', getattr(function, '__defaults__', None)) or () numdefaults = len(defaults) if numdefaults: return argnames[startindex:-numdefaults] return argnames[startindex:] - + def fillfuncargs(function): - """ fill missing funcargs. """ + """ fill missing funcargs. """ request = FuncargRequest(pyfuncitem=function) request._fillfuncargs() @@ -29,10 +29,10 @@ def getplugins(node, withpy=False): # might by any node _notexists = object() class CallSpec: def __init__(self, funcargs, id, param): - self.funcargs = funcargs + self.funcargs = funcargs self.id = id if param is not _notexists: - self.param = param + self.param = param def __repr__(self): return "" %( self.id, getattr(self, 'param', '?'), self.funcargs) @@ -40,7 +40,7 @@ class CallSpec: class Metafunc: def __init__(self, function, config=None, cls=None, module=None): self.config = config - self.module = module + self.module = module self.function = function self.funcargnames = getfuncargnames(function) self.cls = cls @@ -51,7 +51,7 @@ class Metafunc: def addcall(self, funcargs=None, id=_notexists, param=_notexists): assert funcargs is None or isinstance(funcargs, dict) if id is None: - raise ValueError("id=None not allowed") + raise ValueError("id=None not allowed") if id is _notexists: id = len(self._calls) id = str(id) @@ -65,7 +65,7 @@ class FuncargRequest: _argname = None class LookupError(LookupError): - """ error on performing funcarg request. """ + """ error on performing funcarg request. """ def __init__(self, pyfuncitem): self._pyfuncitem = pyfuncitem @@ -77,7 +77,7 @@ class FuncargRequest: self.config = pyfuncitem.config self.fspath = pyfuncitem.fspath if hasattr(pyfuncitem, '_requestparam'): - self.param = pyfuncitem._requestparam + self.param = pyfuncitem._requestparam self._plugins = getplugins(pyfuncitem, withpy=True) self._funcargs = self._pyfuncitem.funcargs.copy() self._name2factory = {} @@ -94,39 +94,39 @@ class FuncargRequest: def applymarker(self, marker): - """ apply a marker to a test function invocation. + """ apply a marker to a test function invocation. - The 'marker' must be created with py.test.mark.* XYZ. + The 'marker' must be created with py.test.mark.* XYZ. """ if not isinstance(marker, py.test.mark.XYZ.__class__): raise ValueError("%r is not a py.test.mark.* object") - self._pyfuncitem.keywords[marker.markname] = marker + self._pyfuncitem.keywords[marker.markname] = marker def cached_setup(self, setup, teardown=None, scope="module", extrakey=None): - """ cache and return result of calling setup(). + """ cache and return result of calling setup(). - The requested argument name, the scope and the ``extrakey`` - determine the cache key. The scope also determines when - teardown(result) will be called. valid scopes are: - scope == 'function': when the single test function run finishes. + The requested argument name, the scope and the ``extrakey`` + determine the cache key. The scope also determines when + teardown(result) will be called. valid scopes are: + scope == 'function': when the single test function run finishes. scope == 'module': when tests in a different module are run - scope == 'session': when tests of the session have run. + scope == 'session': when tests of the session have run. """ if not hasattr(self.config, '_setupcache'): - self.config._setupcache = {} # XXX weakref? + self.config._setupcache = {} # XXX weakref? cachekey = (self._currentarg, self._getscopeitem(scope), extrakey) cache = self.config._setupcache try: val = cache[cachekey] except KeyError: val = setup() - cache[cachekey] = val + cache[cachekey] = val if teardown is not None: def finalizer(): del cache[cachekey] teardown(val) self._addfinalizer(finalizer, scope=scope) - return val + return val def getfuncargvalue(self, argname): try: @@ -135,15 +135,15 @@ class FuncargRequest: pass if argname not in self._name2factory: self._name2factory[argname] = self.config.pluginmanager.listattr( - plugins=self._plugins, + plugins=self._plugins, attrname=self._argprefix + str(argname) ) - #else: we are called recursively + #else: we are called recursively if not self._name2factory[argname]: self._raiselookupfailed(argname) funcargfactory = self._name2factory[argname].pop() oldarg = self._currentarg - self._currentarg = argname + self._currentarg = argname try: self._funcargs[argname] = res = funcargfactory(request=self) finally: @@ -165,8 +165,8 @@ class FuncargRequest: finalizer=finalizer, colitem=colitem) def addfinalizer(self, finalizer): - """ call the given finalizer after test function finished execution. """ - self._addfinalizer(finalizer, scope="function") + """ call the given finalizer after test function finished execution. """ + self._addfinalizer(finalizer, scope="function") def __repr__(self): return "" %(self._pyfuncitem) @@ -178,7 +178,7 @@ class FuncargRequest: if name.startswith(self._argprefix): name = name[len(self._argprefix):] if name not in available: - available.append(name) + available.append(name) fspath, lineno, msg = self._pyfuncitem.reportinfo() msg = "LookupError: no factory found for function argument %r" % (argname,) msg += "\n available funcargs: %s" %(", ".join(available),) diff --git a/py/_test/parseopt.py b/py/_test/parseopt.py index 8e282f337..36af25628 100644 --- a/py/_test/parseopt.py +++ b/py/_test/parseopt.py @@ -1,5 +1,5 @@ """ -thin wrapper around Python's optparse.py +thin wrapper around Python's optparse.py adding some extra checks and ways to systematically have Environment variables provide default values for options. basic usage: @@ -7,23 +7,23 @@ for options. basic usage: >>> parser = Parser() >>> parser.addoption("--hello", action="store_true", dest="hello") >>> option, args = parser.parse(['--hello']) - >>> option.hello + >>> option.hello True >>> args [] - + """ import py -import optparse +import optparse class Parser: - """ Parser for command line arguments. """ + """ Parser for command line arguments. """ def __init__(self, usage=None, processopt=None): self._anonymous = OptionGroup("custom options", parser=self) self._groups = [] self._processopt = processopt - self._usage = usage + self._usage = usage self.hints = [] def processoption(self, option): @@ -44,9 +44,9 @@ class Parser: if grp.name == after: break self._groups.insert(i+1, group) - return group + return group - addgroup = getgroup + addgroup = getgroup def addgroup(self, name, description=""): py.log._apiwarn("1.1", "use getgroup() which gets-or-creates") return self.getgroup(name, description) @@ -60,7 +60,7 @@ class Parser: groups = self._groups + [self._anonymous] for group in groups: if group.options: - desc = group.description or group.name + desc = group.description or group.name optgroup = optparse.OptionGroup(optparser, desc) optgroup.add_options(group.options) optparser.add_option_group(optgroup) @@ -78,7 +78,7 @@ class OptionGroup: self.name = name self.description = description self.options = [] - self.parser = parser + self.parser = parser def addoption(self, *optnames, **attrs): """ add an option to this group. """ @@ -92,7 +92,7 @@ class OptionGroup: def _addoption_instance(self, option, shortupper=False): if not shortupper: for opt in option._short_opts: - if opt[0] == '-' and opt[1].islower(): + if opt[0] == '-' and opt[1].islower(): raise ValueError("lowercase shortoptions reserved") if self.parser: self.parser.processoption(option) @@ -101,10 +101,10 @@ class OptionGroup: class MyOptionParser(optparse.OptionParser): def __init__(self, parser): - self._parser = parser + self._parser = parser optparse.OptionParser.__init__(self, usage=parser._usage) def format_epilog(self, formatter): - hints = self._parser.hints + hints = self._parser.hints if hints: s = "\n".join(["hint: " + x for x in hints]) + "\n" s = "\n" + s + "\n" diff --git a/py/_test/pluginmanager.py b/py/_test/pluginmanager.py index 3d5377467..e6a0895ce 100644 --- a/py/_test/pluginmanager.py +++ b/py/_test/pluginmanager.py @@ -1,5 +1,5 @@ """ -managing loading and interacting with pytest plugins. +managing loading and interacting with pytest plugins. """ import py import inspect @@ -11,7 +11,7 @@ default_plugins = ( "junitxml doctest").split() def check_old_use(mod, modname): - clsname = modname[len('pytest_'):].capitalize() + "Plugin" + clsname = modname[len('pytest_'):].capitalize() + "Plugin" assert not hasattr(mod, clsname), (mod, clsname) class PluginManager(object): @@ -19,7 +19,7 @@ class PluginManager(object): self.registry = Registry() self._name2plugin = {} self._hints = [] - self.hook = HookRelay([hookspec], registry=self.registry) + self.hook = HookRelay([hookspec], registry=self.registry) self.register(self) for spec in default_plugins: self.import_plugin(spec) @@ -29,8 +29,8 @@ class PluginManager(object): if hasattr(plugin, '__name__'): name = plugin.__name__.split(".")[-1] else: - name = id(plugin) - return name + name = id(plugin) + return name def register(self, plugin, name=None): assert not self.isregistered(plugin), plugin @@ -83,14 +83,14 @@ class PluginManager(object): impname = canonical_importname(name) return self._name2plugin[impname] - # API for bootstrapping + # API for bootstrapping # def _envlist(self, varname): val = py.std.os.environ.get(varname, None) if val is not None: return val.split(',') return () - + def consider_env(self): for spec in self._envlist("PYTEST_PLUGINS"): self.import_plugin(spec) @@ -99,7 +99,7 @@ class PluginManager(object): try: from pkg_resources import iter_entry_points except ImportError: - return # XXX issue a warning + return # XXX issue a warning for ep in iter_entry_points('pytest11'): name = canonical_importname(ep.name) if name in self._name2plugin: @@ -109,7 +109,7 @@ class PluginManager(object): def consider_preparse(self, args): for opt1,opt2 in zip(args, args[1:]): - if opt1 == "-p": + if opt1 == "-p": self.import_plugin(opt2) def consider_conftest(self, conftestmodule): @@ -126,7 +126,7 @@ class PluginManager(object): if not isinstance(attr, (list, tuple)): attr = (attr,) for spec in attr: - self.import_plugin(spec) + self.import_plugin(spec) def import_plugin(self, spec): assert isinstance(spec, str) @@ -141,7 +141,7 @@ class PluginManager(object): e = py.std.sys.exc_info()[1] self._hints.append("skipped plugin %r: %s" %((modname, e.msg))) else: - check_old_use(mod, modname) + check_old_use(mod, modname) self.register(mod) self.consider_module(mod) @@ -151,11 +151,11 @@ class PluginManager(object): for hint in self._hints: tw.line("hint: %s" % hint) - # # - # API for interacting with registered and instantiated plugin objects # - # + # API for interacting with registered and instantiated plugin objects + # + # def listattr(self, attrname, plugins=None): return self.registry.listattr(attrname, plugins=plugins) @@ -177,14 +177,14 @@ class PluginManager(object): setattr(py.test, name, value) py.test.__all__.append(name) if hasattr(self, '_config'): - self.call_plugin(plugin, "pytest_addoption", + self.call_plugin(plugin, "pytest_addoption", {'parser': self._config._parser}) - self.call_plugin(plugin, "pytest_configure", + self.call_plugin(plugin, "pytest_configure", {'config': self._config}) def call_plugin(self, plugin, methname, kwargs): return MultiCall( - methods=self.listattr(methname, plugins=[plugin]), + methods=self.listattr(methname, plugins=[plugin]), kwargs=kwargs, firstresult=True).execute() def do_configure(self, config): @@ -193,8 +193,8 @@ class PluginManager(object): config.hook.pytest_configure(config=self._config) def do_unconfigure(self, config): - config = self._config - del self._config + config = self._config + del self._config config.hook.pytest_unconfigure(config=config) config.pluginmanager.unregister(self) @@ -202,25 +202,25 @@ def canonical_importname(name): name = name.lower() modprefix = "pytest_" if not name.startswith(modprefix): - name = modprefix + name - return name + name = modprefix + name + return name def importplugin(importspec): try: - return __import__(importspec) + return __import__(importspec) except ImportError: e = py.std.sys.exc_info()[1] if str(e).find(importspec) == -1: raise try: - return __import__("py._plugin.%s" %(importspec), + return __import__("py._plugin.%s" %(importspec), None, None, '__doc__') except ImportError: e = py.std.sys.exc_info()[1] if str(e).find(importspec) == -1: raise # show the original exception, not the failing internal one - return __import__(importspec) + return __import__(importspec) class MultiCall: @@ -243,11 +243,11 @@ class MultiCall: kwargs = self.getkwargs(method) res = method(**kwargs) if res is not None: - self.results.append(res) + self.results.append(res) if self.firstresult: return res if not self.firstresult: - return self.results + return self.results def getkwargs(self, method): kwargs = {} @@ -256,7 +256,7 @@ class MultiCall: kwargs[argname] = self.kwargs[argname] except KeyError: pass # might be optional param - return kwargs + return kwargs def varnames(func): ismethod = inspect.ismethod(func) @@ -268,7 +268,7 @@ def varnames(func): class Registry: """ - Manage Plugins: register/unregister call calls to plugins. + Manage Plugins: register/unregister call calls to plugins. """ def __init__(self, plugins=None): if plugins is None: @@ -284,7 +284,7 @@ class Registry: self._plugins.remove(plugin) def isregistered(self, plugin): - return plugin in self._plugins + return plugin in self._plugins def __iter__(self): return iter(self._plugins) @@ -297,12 +297,12 @@ class Registry: try: l.append(getattr(plugin, attrname)) except AttributeError: - continue + continue if reverse: l.reverse() return l -class HookRelay: +class HookRelay: def __init__(self, hookspecs, registry, prefix="pytest_"): if not isinstance(hookspecs, list): hookspecs = [hookspecs] @@ -327,16 +327,16 @@ class HookRelay: if not added: raise ValueError("did not find new %r hooks in %r" %( prefix, hookspecs,)) - + def _performcall(self, name, multicall): return multicall.execute() - + class HookCaller: def __init__(self, hookrelay, name, firstresult): - self.hookrelay = hookrelay - self.name = name - self.firstresult = firstresult + self.hookrelay = hookrelay + self.name = name + self.firstresult = firstresult def __repr__(self): return "" %(self.name,) @@ -350,4 +350,4 @@ class HookCaller: methods = self.hookrelay._registry.listattr(self.name, plugins=plugins) mc = MultiCall(methods, kwargs, firstresult=self.firstresult) return self.hookrelay._performcall(self.name, mc) - + diff --git a/py/_test/pycollect.py b/py/_test/pycollect.py index 0dd785a3b..720e2f1c7 100644 --- a/py/_test/pycollect.py +++ b/py/_test/pycollect.py @@ -1,6 +1,6 @@ """ -Python related collection nodes. -""" +Python related collection nodes. +""" import py import inspect import sys @@ -9,16 +9,16 @@ from py._test import funcargs from py._code.code import TerminalRepr class PyobjMixin(object): - def obj(): + def obj(): def fget(self): - try: - return self._obj - except AttributeError: - self._obj = obj = self._getobj() - return obj - def fset(self, value): - self._obj = value - return property(fget, fset, None, "underlying python object") + try: + return self._obj + except AttributeError: + self._obj = obj = self._getobj() + return obj + def fset(self, value): + self._obj = value + return property(fget, fset, None, "underlying python object") obj = obj() def _getobj(self): @@ -32,7 +32,7 @@ class PyobjMixin(object): for node in chain: if isinstance(node, Instance): continue - name = node.name + name = node.name if isinstance(node, Module): assert name.endswith(".py") name = name[:-3] @@ -61,17 +61,17 @@ class PyobjMixin(object): def reportinfo(self): fspath, lineno = self._getfslineno() modpath = self.getmodpath() - return fspath, lineno, modpath + return fspath, lineno, modpath -class PyCollectorMixin(PyobjMixin, py.test.collect.Collector): +class PyCollectorMixin(PyobjMixin, py.test.collect.Collector): Class = configproperty('Class') Instance = configproperty('Instance') Function = configproperty('Function') Generator = configproperty('Generator') - - def funcnamefilter(self, name): - return name.startswith('test') - def classnamefilter(self, name): + + def funcnamefilter(self, name): + return name.startswith('test') + def classnamefilter(self, name): return name.startswith('Test') def collect(self): @@ -112,7 +112,7 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector): if self.classnamefilter(name) and \ inspect.isclass(obj): if hasinit(obj): - # XXX WARN + # XXX WARN return False return True @@ -120,7 +120,7 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector): module = self.getparent(Module).obj clscol = self.getparent(Class) cls = clscol and clscol.obj or None - metafunc = funcargs.Metafunc(funcobj, config=self.config, + metafunc = funcargs.Metafunc(funcobj, config=self.config, cls=cls, module=module) gentesthook = self.config.hook.pytest_generate_tests plugins = funcargs.getplugins(self, withpy=True) @@ -130,17 +130,17 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector): l = [] for callspec in metafunc._calls: subname = "%s[%s]" %(name, callspec.id) - function = self.Function(name=subname, parent=self, + function = self.Function(name=subname, parent=self, callspec=callspec, callobj=funcobj) l.append(function) return l - + class Module(py.test.collect.File, PyCollectorMixin): def _getobj(self): return self._memoizedcall('_obj', self._importtestmodule) def _importtestmodule(self): - # we assume we are only called once per module + # we assume we are only called once per module try: mod = self.fspath.pyimport(ensuresyspath=True) except SyntaxError: @@ -150,7 +150,7 @@ class Module(py.test.collect.File, PyCollectorMixin): e = sys.exc_info()[1] raise self.CollectError( "import file mismatch:\n" - "imported module %r has this __file__ attribute:\n" + "imported module %r has this __file__ attribute:\n" " %s\n" "which is not the same as the test file we want to collect:\n" " %s\n" @@ -161,12 +161,12 @@ class Module(py.test.collect.File, PyCollectorMixin): self.config.pluginmanager.consider_module(mod) return mod - def setup(self): + def setup(self): if getattr(self.obj, 'disabled', 0): py.log._apiwarn(">1.1.1", "%r uses 'disabled' which is deprecated, " "use pytestmark=..., see pytest_skipping plugin" % (self.obj,)) py.test.skip("%r is disabled" %(self.obj,)) - if hasattr(self.obj, 'setup_module'): + if hasattr(self.obj, 'setup_module'): #XXX: nose compat hack, move to nose plugin # if it takes a positional arg, its probably a py.test style one # so we pass the current module object @@ -175,8 +175,8 @@ class Module(py.test.collect.File, PyCollectorMixin): else: self.obj.setup_module() - def teardown(self): - if hasattr(self.obj, 'teardown_module'): + def teardown(self): + if hasattr(self.obj, 'teardown_module'): #XXX: nose compat hack, move to nose plugin # if it takes a positional arg, its probably a py.test style one # so we pass the current module object @@ -185,7 +185,7 @@ class Module(py.test.collect.File, PyCollectorMixin): else: self.obj.teardown_module() -class Class(PyCollectorMixin, py.test.collect.Collector): +class Class(PyCollectorMixin, py.test.collect.Collector): def collect(self): l = self._deprecated_collect() @@ -193,37 +193,37 @@ class Class(PyCollectorMixin, py.test.collect.Collector): return l return [self.Instance(name="()", parent=self)] - def setup(self): + def setup(self): if getattr(self.obj, 'disabled', 0): py.log._apiwarn(">1.1.1", "%r uses 'disabled' which is deprecated, " "use pytestmark=..., see pytest_skipping plugin" % (self.obj,)) py.test.skip("%r is disabled" %(self.obj,)) setup_class = getattr(self.obj, 'setup_class', None) - if setup_class is not None: - setup_class = getattr(setup_class, 'im_func', setup_class) - setup_class(self.obj) + if setup_class is not None: + setup_class = getattr(setup_class, 'im_func', setup_class) + setup_class(self.obj) - def teardown(self): - teardown_class = getattr(self.obj, 'teardown_class', None) - if teardown_class is not None: - teardown_class = getattr(teardown_class, 'im_func', teardown_class) - teardown_class(self.obj) + def teardown(self): + teardown_class = getattr(self.obj, 'teardown_class', None) + if teardown_class is not None: + teardown_class = getattr(teardown_class, 'im_func', teardown_class) + teardown_class(self.obj) -class Instance(PyCollectorMixin, py.test.collect.Collector): - def _getobj(self): - return self.parent.obj() - def Function(self): - return getattr(self.obj, 'Function', +class Instance(PyCollectorMixin, py.test.collect.Collector): + def _getobj(self): + return self.parent.obj() + def Function(self): + return getattr(self.obj, 'Function', PyCollectorMixin.Function.__get__(self)) # XXX for python 2.2 def _keywords(self): return [] Function = property(Function) #def __repr__(self): - # return "<%s of '%s'>" %(self.__class__.__name__, + # return "<%s of '%s'>" %(self.__class__.__name__, # self.parent.obj.__name__) - def newinstance(self): + def newinstance(self): self.obj = self._getobj() return self.obj @@ -231,43 +231,43 @@ class FunctionMixin(PyobjMixin): """ mixin for the code common to Function and Generator. """ - def setup(self): + def setup(self): """ perform setup for this test function. """ if inspect.ismethod(self.obj): - name = 'setup_method' - else: - name = 'setup_function' + name = 'setup_method' + else: + name = 'setup_function' if isinstance(self.parent, Instance): obj = self.parent.newinstance() self.obj = self._getobj() else: - obj = self.parent.obj + obj = self.parent.obj setup_func_or_method = getattr(obj, name, None) - if setup_func_or_method is not None: - setup_func_or_method(self.obj) + if setup_func_or_method is not None: + setup_func_or_method(self.obj) - def teardown(self): + def teardown(self): """ perform teardown for this test function. """ if inspect.ismethod(self.obj): - name = 'teardown_method' - else: - name = 'teardown_function' - obj = self.parent.obj + name = 'teardown_method' + else: + name = 'teardown_function' + obj = self.parent.obj teardown_func_or_meth = getattr(obj, name, None) - if teardown_func_or_meth is not None: - teardown_func_or_meth(self.obj) + if teardown_func_or_meth is not None: + teardown_func_or_meth(self.obj) def _prunetraceback(self, traceback): - if hasattr(self, '_obj') and not self.config.option.fulltrace: - code = py.code.Code(self.obj) - path, firstlineno = code.path, code.firstlineno + if hasattr(self, '_obj') and not self.config.option.fulltrace: + code = py.code.Code(self.obj) + path, firstlineno = code.path, code.firstlineno ntraceback = traceback.cut(path=path, firstlineno=firstlineno) if ntraceback == traceback: ntraceback = ntraceback.cut(path=path) if ntraceback == traceback: ntraceback = ntraceback.cut(excludepath=py._pydir) traceback = ntraceback.filter() - return traceback + return traceback def _repr_failure_py(self, excinfo, style="long"): if excinfo.errisinstance(funcargs.FuncargRequest.LookupError): @@ -277,12 +277,12 @@ class FunctionMixin(PyobjMixin): if line.strip().startswith('def'): return FuncargLookupErrorRepr(fspath, lineno, lines[:i+1], str(excinfo.value)) - return super(FunctionMixin, self)._repr_failure_py(excinfo, + return super(FunctionMixin, self)._repr_failure_py(excinfo, style=style) def repr_failure(self, excinfo, outerr=None): assert outerr is None, "XXX outerr usage is deprecated" - return self._repr_failure_py(excinfo, + return self._repr_failure_py(excinfo, style=self.config.getvalue("tbstyle")) shortfailurerepr = "F" @@ -303,17 +303,17 @@ class FuncargLookupErrorRepr(TerminalRepr): tw.line() tw.line("%s:%d" % (self.filename, self.firstlineno+1)) -class Generator(FunctionMixin, PyCollectorMixin, py.test.collect.Collector): +class Generator(FunctionMixin, PyCollectorMixin, py.test.collect.Collector): def collect(self): - # test generators are seen as collectors but they also - # invoke setup/teardown on popular request + # test generators are seen as collectors but they also + # invoke setup/teardown on popular request # (induced by the common "test_*" naming shared with normal tests) - self.config._setupstate.prepare(self) + self.config._setupstate.prepare(self) l = [] seen = {} - for i, x in enumerate(self.obj()): + for i, x in enumerate(self.obj()): name, call, args = self.getcallargs(x) - if not py.builtin.callable(call): + if not py.builtin.callable(call): raise TypeError("%r yielded non callable test %r" %(self.obj, call,)) if name is None: name = "[%d]" % i @@ -324,7 +324,7 @@ class Generator(FunctionMixin, PyCollectorMixin, py.test.collect.Collector): seen[name] = True l.append(self.Function(name, self, args=args, callobj=call)) return l - + def getcallargs(self, obj): if not isinstance(obj, (tuple, list)): obj = (obj,) @@ -335,34 +335,34 @@ class Generator(FunctionMixin, PyCollectorMixin, py.test.collect.Collector): else: name = None call, args = obj[0], obj[1:] - return name, call, args - + return name, call, args + # -# Test Items +# Test Items # _dummy = object() -class Function(FunctionMixin, py.test.collect.Item): - """ a Function Item is responsible for setting up +class Function(FunctionMixin, py.test.collect.Item): + """ a Function Item is responsible for setting up and executing a Python callable test object. """ _genid = None def __init__(self, name, parent=None, args=None, config=None, callspec=None, callobj=_dummy): super(Function, self).__init__(name, parent, config=config) - self._args = args + self._args = args if self._isyieldedfunction(): - assert not callspec, "yielded functions (deprecated) cannot have funcargs" + assert not callspec, "yielded functions (deprecated) cannot have funcargs" else: if callspec is not None: self.funcargs = callspec.funcargs or {} - self._genid = callspec.id + self._genid = callspec.id if hasattr(callspec, "param"): self._requestparam = callspec.param else: self.funcargs = {} - if callobj is not _dummy: - self._obj = callobj + if callobj is not _dummy: + self._obj = callobj self.function = getattr(self.obj, 'im_func', self.obj) self.keywords.update(py.builtin._getfuncdict(self.obj) or {}) @@ -382,17 +382,17 @@ class Function(FunctionMixin, py.test.collect.Item): def setup(self): super(Function, self).setup() - if hasattr(self, 'funcargs'): + if hasattr(self, 'funcargs'): funcargs.fillfuncargs(self) def __eq__(self, other): try: - return (self.name == other.name and + return (self.name == other.name and self._args == other._args and self.parent == other.parent and - self.obj == other.obj and - getattr(self, '_genid', None) == - getattr(other, '_genid', None) + self.obj == other.obj and + getattr(self, '_genid', None) == + getattr(other, '_genid', None) ) except AttributeError: pass @@ -400,7 +400,7 @@ class Function(FunctionMixin, py.test.collect.Item): def __ne__(self, other): return not self == other - + def __hash__(self): return hash((self.parent, self.name)) diff --git a/py/_test/session.py b/py/_test/session.py index 66ea640ab..64d724d13 100644 --- a/py/_test/session.py +++ b/py/_test/session.py @@ -1,8 +1,8 @@ -""" basic test session implementation. +""" basic test session implementation. -* drives collection of tests -* triggers executions of tests -* produces events used by reporting +* drives collection of tests +* triggers executions of tests +* produces events used by reporting """ import py @@ -18,15 +18,15 @@ EXIT_NOHOSTS = 4 Item = py.test.collect.Item Collector = py.test.collect.Collector -class Session(object): +class Session(object): nodeid = "" class Interrupted(KeyboardInterrupt): """ signals an interrupted test run. """ __module__ = 'builtins' # for py3 - + def __init__(self, config): self.config = config - self.pluginmanager = config.pluginmanager # shortcut + self.pluginmanager = config.pluginmanager # shortcut self.pluginmanager.register(self) self._testsfailed = 0 self._nomatch = False @@ -36,34 +36,34 @@ class Session(object): """ yield Items from iterating over the given colitems. """ if colitems: colitems = list(colitems) - while colitems: + while colitems: next = colitems.pop(0) if isinstance(next, (tuple, list)): - colitems[:] = list(next) + colitems + colitems[:] = list(next) + colitems continue assert self.pluginmanager is next.config.pluginmanager if isinstance(next, Item): remaining = self.filteritems([next]) if remaining: self.config.hook.pytest_itemstart(item=next) - yield next + yield next else: assert isinstance(next, Collector) self.config.hook.pytest_collectstart(collector=next) rep = self.config.hook.pytest_make_collect_report(collector=next) if rep.passed: for x in self.genitems(rep.result, keywordexpr): - yield x + yield x self.config.hook.pytest_collectreport(report=rep) if self.shouldstop: raise self.Interrupted(self.shouldstop) def filteritems(self, colitems): """ return items to process (some may be deselected)""" - keywordexpr = self.config.option.keyword + keywordexpr = self.config.option.keyword if not keywordexpr or self._nomatch: return colitems - if keywordexpr[-1] == ":": + if keywordexpr[-1] == ":": keywordexpr = keywordexpr[:-1] remaining = [] deselected = [] @@ -73,13 +73,13 @@ class Session(object): deselected.append(colitem) continue remaining.append(colitem) - if deselected: + if deselected: self.config.hook.pytest_deselected(items=deselected) if self.config.option.keyword.endswith(":"): self._nomatch = True - return remaining + return remaining - def collect(self, colitems): + def collect(self, colitems): keyword = self.config.option.keyword for x in self.genitems(colitems, keyword): yield x @@ -87,7 +87,7 @@ class Session(object): def sessionstarts(self): """ setup any neccessary resources ahead of the test run. """ self.config.hook.pytest_sessionstart(session=self) - + def pytest_runtest_logreport(self, report): if report.failed: self._testsfailed += 1 @@ -98,15 +98,15 @@ class Session(object): pytest_collectreport = pytest_runtest_logreport def sessionfinishes(self, exitstatus): - """ teardown any resources after a test run. """ + """ teardown any resources after a test run. """ self.config.hook.pytest_sessionfinish( - session=self, - exitstatus=exitstatus, + session=self, + exitstatus=exitstatus, ) def main(self, colitems): """ main loop for running tests. """ - self.shouldstop = False + self.shouldstop = False self.sessionstarts() exitstatus = EXIT_OK try: @@ -127,8 +127,8 @@ class Session(object): return exitstatus def _mainloop(self, colitems): - for item in self.collect(colitems): - if not self.config.option.collectonly: + for item in self.collect(colitems): + if not self.config.option.collectonly: item.config.hook.pytest_runtest_protocol(item=item) if self.shouldstop: raise self.Interrupted(self.shouldstop) diff --git a/py/_xmlgen.py b/py/_xmlgen.py index 854fbccae..1bcf959ac 100644 --- a/py/_xmlgen.py +++ b/py/_xmlgen.py @@ -1,14 +1,14 @@ """ module for generating and serializing xml and html structures -by using simple python objects. +by using simple python objects. (c) holger krekel, holger at merlinux eu. 2009 -""" +""" import py import sys, re if sys.version_info >= (3,0): - def u(s): + def u(s): return s def unicode(x): if hasattr(x, '__unicode__'): @@ -17,64 +17,64 @@ if sys.version_info >= (3,0): else: def u(s): return unicode(s) - unicode = unicode - + unicode = unicode -class NamespaceMetaclass(type): - def __getattr__(self, name): - if name[:1] == '_': - raise AttributeError(name) - if self == Namespace: - raise ValueError("Namespace class is abstract") + +class NamespaceMetaclass(type): + def __getattr__(self, name): + if name[:1] == '_': + raise AttributeError(name) + if self == Namespace: + raise ValueError("Namespace class is abstract") tagspec = self.__tagspec__ - if tagspec is not None and name not in tagspec: - raise AttributeError(name) + if tagspec is not None and name not in tagspec: + raise AttributeError(name) classattr = {} - if self.__stickyname__: - classattr['xmlname'] = name - cls = type(name, (self.__tagclass__,), classattr) - setattr(self, name, cls) - return cls + if self.__stickyname__: + classattr['xmlname'] = name + cls = type(name, (self.__tagclass__,), classattr) + setattr(self, name, cls) + return cls class Tag(list): - class Attr(object): - def __init__(self, **kwargs): - self.__dict__.update(kwargs) + class Attr(object): + def __init__(self, **kwargs): + self.__dict__.update(kwargs) def __init__(self, *args, **kwargs): super(Tag, self).__init__(args) - self.attr = self.Attr(**kwargs) + self.attr = self.Attr(**kwargs) def __unicode__(self): - return self.unicode(indent=0) + return self.unicode(indent=0) __str__ = __unicode__ def unicode(self, indent=2): l = [] - SimpleUnicodeVisitor(l.append, indent).visit(self) - return "".join(l) + SimpleUnicodeVisitor(l.append, indent).visit(self) + return "".join(l) def __repr__(self): - name = self.__class__.__name__ + name = self.__class__.__name__ return "<%r tag object %d>" % (name, id(self)) - + Namespace = NamespaceMetaclass('Namespace', (object, ), { - '__tagspec__': None, - '__tagclass__': Tag, - '__stickyname__': False, + '__tagspec__': None, + '__tagclass__': Tag, + '__stickyname__': False, }) -class HtmlTag(Tag): +class HtmlTag(Tag): def unicode(self, indent=2): l = [] - HtmlVisitor(l.append, indent, shortempty=False).visit(self) - return u("").join(l) + HtmlVisitor(l.append, indent, shortempty=False).visit(self) + return u("").join(l) -# exported plain html namespace +# exported plain html namespace class html(Namespace): __tagclass__ = HtmlTag - __stickyname__ = True - __tagspec__ = dict([(x,1) for x in ( + __stickyname__ = True + __tagspec__ = dict([(x,1) for x in ( 'a,abbr,acronym,address,applet,area,b,bdo,big,blink,' 'blockquote,body,br,button,caption,center,cite,code,col,' 'colgroup,comment,dd,del,dfn,dir,div,dl,dt,em,embed,' @@ -87,11 +87,11 @@ class html(Namespace): 'base,basefont,frame,hr,isindex,param,samp,var' ).split(',') if x]) - class Style(object): - def __init__(self, **kw): + class Style(object): + def __init__(self, **kw): for x, y in kw.items(): x = x.replace('_', '-') - setattr(self, x, y) + setattr(self, x, y) class raw(object): @@ -102,94 +102,94 @@ class raw(object): class SimpleUnicodeVisitor(object): """ recursive visitor to write unicode. """ - def __init__(self, write, indent=0, curindent=0, shortempty=True): + def __init__(self, write, indent=0, curindent=0, shortempty=True): self.write = write self.cache = {} self.visited = {} # for detection of recursion - self.indent = indent + self.indent = indent self.curindent = curindent self.parents = [] - self.shortempty = shortempty # short empty tags or not + self.shortempty = shortempty # short empty tags or not - def visit(self, node): + def visit(self, node): """ dispatcher on node's class/bases name. """ cls = node.__class__ try: - visitmethod = self.cache[cls] + visitmethod = self.cache[cls] except KeyError: - for subclass in cls.__mro__: + for subclass in cls.__mro__: visitmethod = getattr(self, subclass.__name__, None) if visitmethod is not None: break else: - visitmethod = self.object + visitmethod = self.object self.cache[cls] = visitmethod - visitmethod(node) + visitmethod(node) def object(self, obj): - #self.write(obj) + #self.write(obj) self.write(escape(unicode(obj))) def raw(self, obj): - self.write(obj.uniobj) + self.write(obj.uniobj) - def list(self, obj): + def list(self, obj): assert id(obj) not in self.visited self.visited[id(obj)] = 1 - map(self.visit, obj) + map(self.visit, obj) def Tag(self, tag): assert id(tag) not in self.visited - try: + try: tag.parent = self.parents[-1] - except IndexError: - tag.parent = None + except IndexError: + tag.parent = None self.visited[id(tag)] = 1 tagname = getattr(tag, 'xmlname', tag.__class__.__name__) if self.curindent and not self._isinline(tagname): - self.write("\n" + u(' ') * self.curindent) + self.write("\n" + u(' ') * self.curindent) if tag: - self.curindent += self.indent + self.curindent += self.indent self.write(u('<%s%s>') % (tagname, self.attributes(tag))) - self.parents.append(tag) + self.parents.append(tag) for x in tag: self.visit(x) - self.parents.pop() - self.write(u('') % tagname) - self.curindent -= self.indent + self.parents.pop() + self.write(u('') % tagname) + self.curindent -= self.indent else: - nameattr = tagname+self.attributes(tag) - if self._issingleton(tagname): + nameattr = tagname+self.attributes(tag) + if self._issingleton(tagname): self.write(u('<%s/>') % (nameattr,)) - else: + else: self.write(u('<%s>') % (nameattr, tagname)) def attributes(self, tag): # serialize attributes - attrlist = dir(tag.attr) - attrlist.sort() + attrlist = dir(tag.attr) + attrlist.sort() l = [] - for name in attrlist: + for name in attrlist: res = self.repr_attribute(tag.attr, name) - if res is not None: - l.append(res) + if res is not None: + l.append(res) l.extend(self.getstyle(tag)) return u("").join(l) - def repr_attribute(self, attrs, name): - if name[:2] != '__': - value = getattr(attrs, name) - if name.endswith('_'): + def repr_attribute(self, attrs, name): + if name[:2] != '__': + value = getattr(attrs, name) + if name.endswith('_'): name = name[:-1] return ' %s="%s"' % (name, escape(unicode(value))) - def getstyle(self, tag): - """ return attribute list suitable for styling. """ - try: + def getstyle(self, tag): + """ return attribute list suitable for styling. """ + try: styledict = tag.style.__dict__ - except AttributeError: - return [] - else: + except AttributeError: + return [] + else: stylelist = [x+': ' + y for x,y in styledict.items()] return [u(' style="%s"') % u('; ').join(stylelist)] @@ -201,9 +201,9 @@ class SimpleUnicodeVisitor(object): """can (and will) be overridden in subclasses""" return False -class HtmlVisitor(SimpleUnicodeVisitor): - - single = dict([(x, 1) for x in +class HtmlVisitor(SimpleUnicodeVisitor): + + single = dict([(x, 1) for x in ('br,img,area,param,col,hr,meta,link,base,' 'input,frame').split(',')]) inline = dict([(x, 1) for x in @@ -211,12 +211,12 @@ class HtmlVisitor(SimpleUnicodeVisitor): 'i img input kbd label q s samp select small span strike ' 'strong sub sup textarea tt u var'.split(' '))]) - def repr_attribute(self, attrs, name): + def repr_attribute(self, attrs, name): if name == 'class_': - value = getattr(attrs, name) - if value is None: + value = getattr(attrs, name) + if value is None: return - return super(HtmlVisitor, self).repr_attribute(attrs, name) + return super(HtmlVisitor, self).repr_attribute(attrs, name) def _issingleton(self, tagname): return tagname in self.single @@ -224,11 +224,11 @@ class HtmlVisitor(SimpleUnicodeVisitor): def _isinline(self, tagname): return tagname in self.inline - + class _escape: def __init__(self): self.escape = { - u('"') : u('"'), u('<') : u('<'), u('>') : u('>'), + u('"') : u('"'), u('<') : u('<'), u('>') : u('>'), u('&') : u('&'), u("'") : u('''), } self.charef_rex = re.compile(u("|").join(self.escape.keys())) diff --git a/setup.py b/setup.py index 4564c8946..34d817cdd 100644 --- a/setup.py +++ b/setup.py @@ -60,18 +60,18 @@ def main(): def cmdline_entrypoints(versioninfo, platform, basename): if platform.startswith('java'): - points = {'py.test-jython': 'py.cmdline:pytest', + points = {'py.test-jython': 'py.cmdline:pytest', 'py.which-jython': 'py.cmdline:pywhich'} else: if basename.startswith("pypy"): - points = {'py.test-%s' % basename: 'py.cmdline:pytest', + points = {'py.test-%s' % basename: 'py.cmdline:pytest', 'py.which-%s' % basename: 'py.cmdline:pywhich',} else: # cpython points = { 'py.test-%s.%s' % versioninfo[:2] : 'py.cmdline:pytest', 'py.which-%s.%s' % versioninfo[:2] : 'py.cmdline:pywhich' } - for x in ['py.cleanup', 'py.convert_unittest', 'py.countloc', + for x in ['py.cleanup', 'py.convert_unittest', 'py.countloc', 'py.lookup', 'py.svnwcrevert', 'py.which', 'py.test']: points[x] = "py.cmdline:%s" % x.replace('.','') return points diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index ddde21d37..428f2cba5 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -38,7 +38,7 @@ class TestGeneralUsage: result = testdir.runpytest(p, '--basetemp=%s' %mytemp) assert result.ret == 0 assert mytemp.join('hello').check() - + def test_assertion_magic(self, testdir): p = testdir.makepyfile(""" def test_this(): @@ -47,7 +47,7 @@ class TestGeneralUsage: """) result = testdir.runpytest(p) result.stdout.fnmatch_lines([ - "> assert x", + "> assert x", "E assert 0", ]) assert result.ret == 1 @@ -120,7 +120,7 @@ class TestGeneralUsage: result.stdout.fnmatch_lines([ "*1 skip*" ]) - + @py.test.mark.xfail def test_issue88_initial_file_multinodes(self, testdir): @@ -135,8 +135,8 @@ class TestGeneralUsage: p = testdir.makepyfile("def test_hello(): pass") result = testdir.runpytest(p, "--collectonly") result.stdout.fnmatch_lines([ - "*MyFile*test_issue88*", - "*Module*test_issue88*", + "*MyFile*test_issue88*", + "*Module*test_issue88*", ]) @py.test.mark.xfail diff --git a/testing/cmdline/__init__.py b/testing/cmdline/__init__.py index 16e385321..792d60054 100644 --- a/testing/cmdline/__init__.py +++ b/testing/cmdline/__init__.py @@ -1 +1 @@ -# +# diff --git a/testing/cmdline/test_cmdline.py b/testing/cmdline/test_cmdline.py index 18b055eba..cc3ce1399 100644 --- a/testing/cmdline/test_cmdline.py +++ b/testing/cmdline/test_cmdline.py @@ -74,7 +74,7 @@ class TestPyCleanup: subdir.mkdir("dist") result = testdir.runpybin("py.cleanup", opt, subdir) assert result.ret == 0 - assert okbuild.check() + assert okbuild.check() assert egg1.check() assert egg2.check() assert subdir.join("preserved1").check() diff --git a/testing/cmdline/test_convert_unittest.py b/testing/cmdline/test_convert_unittest.py index 2bfcd9c2b..952aa574e 100644 --- a/testing/cmdline/test_convert_unittest.py +++ b/testing/cmdline/test_convert_unittest.py @@ -42,7 +42,7 @@ class Test_UTestConvert: assert rewrite_utest("self.assert_(x)") == "assert x" assert rewrite_utest("self.failUnless(func(x)) # XXX") == ( "assert func(x) # XXX") - + assert rewrite_utest( """ self.assert_(1 + f(y) @@ -72,7 +72,7 @@ class Test_UTestConvert: 'Meet the badger.\n') """ ) - + assert rewrite_utest( r""" self.failIf(0 + 0 @@ -95,7 +95,7 @@ class Test_UTestConvert: assert rewrite_utest("self.assertEquals(0, 0)") == ( "assert 0 == 0") - + assert rewrite_utest( r""" self.assertEquals(0, @@ -121,7 +121,7 @@ class Test_UTestConvert: + snake) == 0 """ ) - + assert rewrite_utest( """ self.assertNotEquals(badger + 0 @@ -181,7 +181,7 @@ class Test_UTestConvert: """ ) - + assert rewrite_utest( """ self.assertEquals('''snake snake snake @@ -193,7 +193,7 @@ class Test_UTestConvert: snake snake snake''' == mushroom """ ) - + assert rewrite_utest( """ self.assertEquals(badger(), @@ -205,7 +205,7 @@ class Test_UTestConvert: snake()), 'BAD BADGER' """ ) - + assert rewrite_utest( """ self.assertNotEquals(badger(), @@ -383,7 +383,7 @@ class Test_UTestConvert: expression ... will this blow up? """ ) - + assert rewrite_utest( """ self.failUnless('__builtin__' in modules, "An entry for __builtin__ " @@ -395,7 +395,7 @@ class Test_UTestConvert: "is not in sys.modules.") """ ) - + # two unittests on the same line separated by a semi-colon is # only half-converted. Just so you know. assert rewrite_utest( @@ -407,8 +407,8 @@ class Test_UTestConvert: assert 0 == 0; self.assertEquals(1, 1) #not 2 per line! """ ) - - + + if __name__ == '__main__': unittest.main() diff --git a/testing/code/test_assertion.py b/testing/code/test_assertion.py index 7d2b297f7..d417b0f75 100644 --- a/testing/code/test_assertion.py +++ b/testing/code/test_assertion.py @@ -37,7 +37,7 @@ def test_assert_within_finally(): finally: i = 42 """) - s = excinfo.exconly() + s = excinfo.exconly() assert s.find("takes no argument") != -1 #def g(): @@ -81,9 +81,9 @@ def test_is(): s = str(e) assert s.startswith("assert 1 is 2") -def test_assert_non_string_message(): - class A: - def __str__(self): +def test_assert_non_string_message(): + class A: + def __str__(self): return "hello" try: assert 0 == 1, A() @@ -104,23 +104,23 @@ def test_assert_keyword_arg(): class WeirdRepr: def __repr__(self): return '' - + def bug_test_assert_repr(): v = WeirdRepr() - try: + try: assert v == 1 except AssertionError: e = exvalue() assert e.msg.find('WeirdRepr') != -1 assert e.msg.find('second line') != -1 assert 0 - + def test_assert_non_string(): - try: + try: assert 0, ['list'] except AssertionError: e = exvalue() - assert e.msg.find("list") != -1 + assert e.msg.find("list") != -1 def test_assert_implicit_multiline(): try: @@ -210,7 +210,7 @@ class TestView: return '%s %s %s' % (self.args[0], self.opname, self.args[1]) codelines = [PyOp(op).generate() for op in existing] - assert codelines == ["4 + 5", "getitem('', 'join')", + assert codelines == ["4 + 5", "getitem('', 'join')", "setattr('x', 'y', 3)", "12 - 1"] def test_underscore_api(): diff --git a/testing/code/test_code.py b/testing/code/test_code.py index 13c1fc646..78f15f172 100644 --- a/testing/code/test_code.py +++ b/testing/code/test_code.py @@ -12,9 +12,9 @@ def test_code_gives_back_name_for_not_existing_file(): co_code = compile("pass\n", name, 'exec') assert co_code.co_filename == name code = py.code.Code(co_code) - assert str(code.path) == name + assert str(code.path) == name assert code.fullsource is None - + def test_code_with_class(): class A: pass @@ -56,8 +56,8 @@ def test_getstatement_empty_fullsource(): finally: f.code.__class__.fullsource = prop -def test_code_from_func(): - co = py.code.Code(test_frame_getsourcelineno_myself) +def test_code_from_func(): + co = py.code.Code(test_frame_getsourcelineno_myself) assert co.firstlineno assert co.path @@ -65,7 +65,7 @@ def test_code_from_func(): def test_builtin_patch_unpatch(monkeypatch): cpy_builtin = py.builtin.builtins - comp = cpy_builtin.compile + comp = cpy_builtin.compile def mycompile(*args, **kwargs): return comp(*args, **kwargs) class Sub(AssertionError): @@ -76,8 +76,8 @@ def test_builtin_patch_unpatch(monkeypatch): assert cpy_builtin.AssertionError != Sub assert cpy_builtin.compile != mycompile py.code.unpatch_builtins() - assert cpy_builtin.AssertionError is Sub - assert cpy_builtin.compile == mycompile + assert cpy_builtin.AssertionError is Sub + assert cpy_builtin.compile == mycompile def test_unicode_handling(): @@ -90,7 +90,7 @@ def test_unicode_handling(): u = unicode(excinfo) def test_unicode_or_repr(): - from py._code.code import unicode_or_repr + from py._code.code import unicode_or_repr assert unicode_or_repr('hello') == "hello" if sys.version_info[0] < 3: s = unicode_or_repr('\xf6\xc4\x85') diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 7c142fe52..e8db92c83 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -5,7 +5,7 @@ queue = py.builtin._tryimport('queue', 'Queue') failsonjython = py.test.mark.xfail("sys.platform.startswith('java')") -class TWMock: +class TWMock: def __init__(self): self.lines = [] def sep(self, sep, line=None): @@ -58,18 +58,18 @@ def h(): g() # -class TestTraceback_f_g_h: - def setup_method(self, method): +class TestTraceback_f_g_h: + def setup_method(self, method): try: h() except ValueError: self.excinfo = py.code.ExceptionInfo() def test_traceback_entries(self): - tb = self.excinfo.traceback - entries = list(tb) - assert len(tb) == 4 # maybe fragile test - assert len(entries) == 4 # maybe fragile test + tb = self.excinfo.traceback + entries = list(tb) + assert len(tb) == 4 # maybe fragile test + assert len(entries) == 4 # maybe fragile test names = ['f', 'g', 'h'] for entry in entries: try: @@ -79,10 +79,10 @@ class TestTraceback_f_g_h: assert not names def test_traceback_entry_getsource(self): - tb = self.excinfo.traceback + tb = self.excinfo.traceback s = str(tb[-1].getsource() ) assert s.startswith("def f():") - assert s.endswith("raise ValueError") + assert s.endswith("raise ValueError") @failsonjython def test_traceback_entry_getsource_in_construct(self): @@ -93,20 +93,20 @@ class TestTraceback_f_g_h: except somenoname: pass xyz() - """) - try: + """) + try: exec (source.compile()) - except NameError: - tb = py.code.ExceptionInfo().traceback + except NameError: + tb = py.code.ExceptionInfo().traceback print (tb[-1].getsource()) s = str(tb[-1].getsource()) assert s.startswith("def xyz():\n try:") - assert s.endswith("except somenoname:") + assert s.endswith("except somenoname:") def test_traceback_cut(self): co = py.code.Code(f) - path, firstlineno = co.path, co.firstlineno - traceback = self.excinfo.traceback + path, firstlineno = co.path, co.firstlineno + traceback = self.excinfo.traceback newtraceback = traceback.cut(path=path, firstlineno=firstlineno) assert len(newtraceback) == 1 newtraceback = traceback.cut(path=path, lineno=firstlineno+2) @@ -133,8 +133,8 @@ class TestTraceback_f_g_h: n += 1 f(n) excinfo = py.test.raises(RuntimeError, f, 8) - traceback = excinfo.traceback - recindex = traceback.recursionindex() + traceback = excinfo.traceback + recindex = traceback.recursionindex() assert recindex == 3 def test_traceback_no_recursion_index(self): @@ -150,14 +150,14 @@ class TestTraceback_f_g_h: except: reraise_me() excinfo = py.test.raises(RuntimeError, f, 8) - traceback = excinfo.traceback - recindex = traceback.recursionindex() + traceback = excinfo.traceback + recindex = traceback.recursionindex() assert recindex is None def test_traceback_getcrashentry(self): def i(): __tracebackhide__ = True - raise ValueError + raise ValueError def h(): i() def g(): @@ -171,13 +171,13 @@ class TestTraceback_f_g_h: entry = tb.getcrashentry() co = py.code.Code(h) assert entry.frame.code.path == co.path - assert entry.lineno == co.firstlineno + 1 + assert entry.lineno == co.firstlineno + 1 assert entry.frame.code.name == 'h' def test_traceback_getcrashentry_empty(self): def g(): __tracebackhide__ = True - raise ValueError + raise ValueError def f(): __tracebackhide__ = True g() @@ -190,22 +190,22 @@ class TestTraceback_f_g_h: assert entry.lineno == co.firstlineno + 2 assert entry.frame.code.name == 'g' -def hello(x): - x + 5 +def hello(x): + x + 5 -def test_tbentry_reinterpret(): - try: - hello("hello") - except TypeError: - excinfo = py.code.ExceptionInfo() +def test_tbentry_reinterpret(): + try: + hello("hello") + except TypeError: + excinfo = py.code.ExceptionInfo() tbentry = excinfo.traceback[-1] - msg = tbentry.reinterpret() - assert msg.startswith("TypeError: ('hello' + 5)") + msg = tbentry.reinterpret() + assert msg.startswith("TypeError: ('hello' + 5)") def test_excinfo_exconly(): excinfo = py.test.raises(ValueError, h) assert excinfo.exconly().startswith('ValueError') - excinfo = py.test.raises(ValueError, + excinfo = py.test.raises(ValueError, "raise ValueError('hello\\nworld')") msg = excinfo.exconly(tryshort=True) assert msg.startswith('ValueError') @@ -225,19 +225,19 @@ def test_excinfo_str(): def test_excinfo_errisinstance(): excinfo = py.test.raises(ValueError, h) - assert excinfo.errisinstance(ValueError) + assert excinfo.errisinstance(ValueError) def test_excinfo_no_sourcecode(): try: exec ("raise ValueError()") - except ValueError: + except ValueError: excinfo = py.code.ExceptionInfo() s = str(excinfo.traceback[-1]) if py.std.sys.version_info < (2,5): assert s == " File '':1 in ?\n ???\n" else: assert s == " File '':1 in \n ???\n" - + def test_entrysource_Queue_example(): try: queue.Queue().get(timeout=0.001) @@ -260,7 +260,7 @@ def test_codepath_Queue_example(): assert path.basename.lower() == "queue.py" assert path.check() -class TestFormattedExcinfo: +class TestFormattedExcinfo: def pytest_funcarg__importasmod(self, request): def importasmod(source): source = py.code.Source(source) @@ -309,8 +309,8 @@ class TestFormattedExcinfo: source = pr._getentrysource(excinfo.traceback[-1]) lines = pr.get_source(source, 1, excinfo) assert lines == [ - ' def f():', - '> assert 0', + ' def f():', + '> assert 0', 'E assert 0' ] @@ -328,7 +328,7 @@ class TestFormattedExcinfo: def test_repr_many_line_source_not_existing(self): pr = FormattedExcinfo() co = compile(""" -a = 1 +a = 1 raise ValueError() """, "", "exec") try: @@ -365,11 +365,11 @@ raise ValueError() typename = "Foo" def __init__(self): pass - + def exconly(self, tryshort): return "EXC" def errisinstance(self, cls): - return False + return False excinfo = FakeExcinfo() class FakeRawTB(object): @@ -383,14 +383,14 @@ raise ValueError() fail = py.error.ENOENT repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" - + assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" + def test_repr_local(self): p = FormattedExcinfo(showlocals=True) loc = {'y': 5, 'z': 7, 'x': 3, '__builtins__': {}} # __builtins__} - reprlocals = p.repr_locals(loc) - assert reprlocals.lines + reprlocals = p.repr_locals(loc) + assert reprlocals.lines assert reprlocals.lines[0] == '__builtins__ = ' assert reprlocals.lines[1] == 'x = 3' assert reprlocals.lines[2] == 'y = 5' @@ -405,13 +405,13 @@ raise ValueError() excinfo.traceback = excinfo.traceback.filter() p = FormattedExcinfo() reprtb = p.repr_traceback_entry(excinfo.traceback[-1]) - + # test as intermittent entry lines = reprtb.lines assert lines[0] == ' def func1():' assert lines[1] == '> raise ValueError("hello\\nworld")' - # test as last entry + # test as last entry p = FormattedExcinfo(showlocals=True) repr_entry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) lines = repr_entry.lines @@ -422,7 +422,7 @@ raise ValueError() assert not lines[4:] loc = repr_entry.reprlocals is not None - loc = repr_entry.reprfileloc + loc = repr_entry.reprfileloc assert loc.path == mod.__file__ assert loc.lineno == 3 #assert loc.message == "ValueError: hello" @@ -467,7 +467,7 @@ raise ValueError() assert basename in str(reprtb.reprfileloc.path) assert reprtb.reprfileloc.lineno == 5 - # test last entry + # test last entry p = FormattedExcinfo(style="short") reprtb = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) lines = reprtb.lines @@ -491,7 +491,7 @@ raise ValueError() reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) lines = reprentry.lines assert lines[0] == 'E ValueError: hello' - assert not lines[1:] + assert not lines[1:] def test_repr_traceback_tbfilter(self, importasmod): mod = importasmod(""" @@ -540,7 +540,7 @@ raise ValueError() f(0) """) excinfo = py.test.raises(ValueError, mod.entry) - + for style in ("long", "short"): p = FormattedExcinfo(style=style) reprtb = p.repr_traceback(excinfo) @@ -548,7 +548,7 @@ raise ValueError() assert reprtb.style == style assert not reprtb.extraline repr = p.repr_excinfo(excinfo) - assert repr.reprtraceback + assert repr.reprtraceback assert len(repr.reprtraceback.reprentries) == len(reprtb.reprentries) assert repr.reprcrash.path.endswith("mod.py") assert repr.reprcrash.message == "ValueError: 0" @@ -596,10 +596,10 @@ raise ValueError() assert str(reprtb) def test_tb_entry_AssertionError(self, importasmod): - # probably this test is a bit redundant + # probably this test is a bit redundant # as py/magic/testing/test_assertion.py # already tests correctness of - # assertion-reinterpretation logic + # assertion-reinterpretation logic mod = importasmod(""" def somefunc(): x = 1 @@ -610,7 +610,7 @@ raise ValueError() excinfo = py.test.raises(AssertionError, mod.somefunc) finally: py.code.unpatch_builtins(assertion=True) - + p = FormattedExcinfo() reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) lines = reprentry.lines @@ -629,8 +629,8 @@ raise ValueError() for showlocals in (True, False): repr = excinfo.getrepr(style=style, showlocals=showlocals) assert isinstance(repr, ReprExceptionInfo) - assert repr.reprtraceback.style == style - + assert repr.reprtraceback.style == style + def test_toterminal_long(self, importasmod): mod = importasmod(""" def g(x): @@ -645,7 +645,7 @@ raise ValueError() repr.toterminal(tw) assert tw.lines[0] == "" tw.lines.pop(0) - assert tw.lines[0] == " def f():" + assert tw.lines[0] == " def f():" assert tw.lines[1] == "> g(3)" assert tw.lines[2] == "" assert tw.lines[3].endswith("mod.py:5: ") @@ -666,13 +666,13 @@ raise ValueError() tw = TWMock() path = py.path.local(mod.__file__) old = path.dirpath().chdir() - try: + try: repr = excinfo.getrepr(abspath=False) repr.toterminal(tw) line = tw.lines[-1] - x = py.path.local().bestrelpath(path) + x = py.path.local().bestrelpath(path) if len(x) < len(str(path)): - assert line == "mod.py:3: ValueError" + assert line == "mod.py:3: ValueError" repr = excinfo.getrepr(abspath=True) repr.toterminal(tw) @@ -682,10 +682,10 @@ raise ValueError() old.chdir() @py.test.mark.multi(reproptions=[ - {'style': style, 'showlocals': showlocals, + {'style': style, 'showlocals': showlocals, 'funcargs': funcargs, 'tbfilter': tbfilter } for style in ("long", "short", "no") - for showlocals in (True, False) + for showlocals in (True, False) for tbfilter in (True, False) for funcargs in (True, False)]) def test_format_excinfo(self, importasmod, reproptions): diff --git a/testing/code/test_source.py b/testing/code/test_source.py index bdedeeff2..ef651c363 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -29,7 +29,7 @@ def test_unicode(): x = Source(unicode("4")) assert str(x) == "4" co = py.code.compile(unicode('u"\xc3\xa5"', 'utf8'), mode='eval') - val = eval(co) + val = eval(co) assert isinstance(val, unicode) def test_source_from_function(): @@ -73,37 +73,37 @@ except ValueError: else: x = 23""" -def test_source_putaround(): - source = Source() +def test_source_putaround(): + source = Source() source = source.putaround(""" if 1: x=1 """) assert str(source).strip() == "if 1:\n x=1" -def test_source_strips(): +def test_source_strips(): source = Source("") assert source == Source() assert str(source) == '' - assert source.strip() == source + assert source.strip() == source -def test_source_strip_multiline(): +def test_source_strip_multiline(): source = Source() source.lines = ["", " hello", " "] - source2 = source.strip() + source2 = source.strip() assert source2.lines == [" hello"] def test_syntaxerror_rerepresentation(): ex = py.test.raises(SyntaxError, py.code.compile, 'xyz xyz') assert ex.value.lineno == 1 - assert ex.value.offset in (4,7) # XXX pypy/jython versus cpython? + assert ex.value.offset in (4,7) # XXX pypy/jython versus cpython? assert ex.value.text.strip(), 'x x' def test_isparseable(): assert Source("hello").isparseable() assert Source("if 1:\n pass").isparseable() assert Source(" \nif 1:\n pass").isparseable() - assert not Source("if 1:\n").isparseable() + assert not Source("if 1:\n").isparseable() assert not Source(" \nif 1:\npass").isparseable() assert not Source(chr(0)).isparseable() @@ -125,12 +125,12 @@ class TestAccesses: assert x == "def f(x):" def test_len(self): - assert len(self.source) == 4 + assert len(self.source) == 4 def test_iter(self): - l = [x for x in self.source] - assert len(l) == 4 - + l = [x for x in self.source] + assert len(l) == 4 + class TestSourceParsingAndCompiling: source = Source("""\ def f(x): @@ -157,11 +157,11 @@ class TestSourceParsingAndCompiling: co1 = gensource(""" def f(): raise KeyError() - """) + """) co2 = gensource(""" def f(): raise ValueError() - """) + """) source1 = py.std.inspect.getsource(co1) assert 'KeyError' in source1 source2 = py.std.inspect.getsource(co2) @@ -179,21 +179,21 @@ class TestSourceParsingAndCompiling: def test_getstatementrange_within_constructs(self): source = Source("""\ try: - try: + try: raise ValueError - except SomeThing: - pass + except SomeThing: + pass finally: 42 """) assert len(source) == 7 - assert source.getstatementrange(0) == (0, 7) - assert source.getstatementrange(1) == (1, 5) + assert source.getstatementrange(0) == (0, 7) + assert source.getstatementrange(1) == (1, 5) assert source.getstatementrange(2) == (2, 3) assert source.getstatementrange(3) == (1, 5) - assert source.getstatementrange(4) == (4, 5) + assert source.getstatementrange(4) == (4, 5) assert source.getstatementrange(5) == (0, 7) - assert source.getstatementrange(6) == (6, 7) + assert source.getstatementrange(6) == (6, 7) def test_getstatementrange_bug(self): source = Source("""\ @@ -236,7 +236,7 @@ class TestSourceParsingAndCompiling: py.builtin.exec_(co, globals()) f(7) excinfo = py.test.raises(AssertionError, "f(6)") - frame = excinfo.traceback[-1].frame + frame = excinfo.traceback[-1].frame stmt = frame.code.fullsource.getstatement(frame.lineno) #print "block", str(block) assert str(stmt).strip().startswith('assert') @@ -253,8 +253,8 @@ class TestSourceParsingAndCompiling: mycode = py.code.Code(self.test_compilefuncs_and_path_sanity) mylineno = mycode.firstlineno - mypath = mycode.path - + mypath = mycode.path + for comp in py.code.compile, py.code.Source.compile: for name in '', None, 'my': yield check, comp, name @@ -319,7 +319,7 @@ def test_getfuncsource_with_multine_string(): pass ''' assert str(py.code.Source(f)).strip() == "def f():\n c = '''while True:\n pass\n'''" - + def test_deindent(): from py._code.source import deindent as deindent @@ -343,8 +343,8 @@ def test_deindent(): @py.test.mark.xfail("sys.version_info[:2] != (2,7)") def test_source_of_class_at_eof_without_newline(tmpdir): - # this test fails because the implicit inspect.getsource(A) below - # does not return the "x = 1" last line. + # this test fails because the implicit inspect.getsource(A) below + # does not return the "x = 1" last line. source = py.code.Source(''' class A(object): def method(self): @@ -385,7 +385,7 @@ def test_findsource(): def x(): pass """) - + src, lineno = findsource(co) assert 'if 1:' in str(src) @@ -394,7 +394,7 @@ def test_findsource(): src, lineno = findsource(d['x']) assert 'if 1:' in str(src) assert src[lineno] == " def x():" - + def test_getfslineno(): from py.code import getfslineno diff --git a/testing/io_/test_capture.py b/testing/io_/test_capture.py index 817103d42..2b30257be 100644 --- a/testing/io_/test_capture.py +++ b/testing/io_/test_capture.py @@ -7,12 +7,12 @@ from py.builtin import print_ if sys.version_info >= (3,0): def tobytes(obj): - if isinstance(obj, str): + if isinstance(obj, str): obj = obj.encode('UTF-8') assert isinstance(obj, bytes) return obj def totext(obj): - if isinstance(obj, bytes): + if isinstance(obj, bytes): obj = str(obj, 'UTF-8') assert isinstance(obj, str) return obj @@ -30,11 +30,11 @@ else: def oswritebytes(fd, obj): os.write(fd, tobytes(obj)) - + class TestTextIO: def test_text(self): f = py.io.TextIO() - f.write("hello") + f.write("hello") s = f.getvalue() assert s == "hello" f.close() @@ -46,10 +46,10 @@ class TestTextIO: py.test.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))") else: f.write(unicode("\u00f6", 'UTF-8')) - f.write("hello") # bytes + f.write("hello") # bytes s = f.getvalue() f.close() - assert isinstance(s, unicode) + assert isinstance(s, unicode) def test_bytes_io(): f = py.io.BytesIO() @@ -61,10 +61,10 @@ def test_bytes_io(): def test_dontreadfrominput(): from py._io.capture import DontReadFromInput f = DontReadFromInput() - assert not f.isatty() + assert not f.isatty() py.test.raises(IOError, f.read) py.test.raises(IOError, f.readlines) - py.test.raises(IOError, iter, f) + py.test.raises(IOError, iter, f) py.test.raises(ValueError, f.fileno) f.close() # just for completeness @@ -77,14 +77,14 @@ def pytest_funcarg__tmpfile(request): @needsdup def test_dupfile(tmpfile): flist = [] - for i in range(5): + for i in range(5): nf = py.io.dupfile(tmpfile, encoding="utf-8") assert nf != tmpfile assert nf.fileno() != tmpfile.fileno() - assert nf not in flist + assert nf not in flist print_(i, end="", file=nf) - flist.append(nf) - for i in range(5): + flist.append(nf) + for i in range(5): f = flist[i] f.close() tmpfile.seek(0) @@ -92,8 +92,8 @@ def test_dupfile(tmpfile): assert "01234" in repr(s) tmpfile.close() -class TestFDCapture: - pytestmark = needsdup +class TestFDCapture: + pytestmark = needsdup def test_not_now(self, tmpfile): fd = tmpfile.fileno() @@ -102,7 +102,7 @@ class TestFDCapture: os.write(fd, data) f = cap.done() s = f.read() - assert not s + assert not s cap = py.io.FDCapture(fd, now=False) cap.start() os.write(fd, data) @@ -143,14 +143,14 @@ class TestFDCapture: py.test.raises(ValueError, cap.start) f.close() - def test_stderr(self): + def test_stderr(self): cap = py.io.FDCapture(2, patchsys=True) print_("hello", file=sys.stderr) f = cap.done() s = f.read() assert s == "hello\n" - def test_stdin(self, tmpfile): + def test_stdin(self, tmpfile): tmpfile.write(tobytes("3")) tmpfile.seek(0) cap = py.io.FDCapture(0, tmpfile=tmpfile) @@ -175,7 +175,7 @@ class TestFDCapture: assert stmp == data2 -class TestStdCapture: +class TestStdCapture: def getcapture(self, **kw): return py.io.StdCapture(**kw) @@ -220,7 +220,7 @@ class TestStdCapture: assert not err def test_capturing_twice_error(self): - cap = self.getcapture() + cap = self.getcapture() print ("hello") out, err = cap.reset() print ("world") @@ -229,54 +229,54 @@ class TestStdCapture: assert not err def test_capturing_modify_sysouterr_in_between(self): - oldout = sys.stdout - olderr = sys.stderr + oldout = sys.stdout + olderr = sys.stderr cap = self.getcapture() sys.stdout.write("hello") sys.stderr.write("world") - sys.stdout = py.io.TextIO() - sys.stderr = py.io.TextIO() + sys.stdout = py.io.TextIO() + sys.stderr = py.io.TextIO() print ("not seen" ) sys.stderr.write("not seen\n") out, err = cap.reset() assert out == "hello" assert err == "world" - assert sys.stdout == oldout - assert sys.stderr == olderr + assert sys.stdout == oldout + assert sys.stderr == olderr def test_capturing_error_recursive(self): - cap1 = self.getcapture() + cap1 = self.getcapture() print ("cap1") - cap2 = self.getcapture() + cap2 = self.getcapture() print ("cap2") out2, err2 = cap2.reset() - out1, err1 = cap1.reset() + out1, err1 = cap1.reset() assert out1 == "cap1\n" assert out2 == "cap2\n" - - def test_just_out_capture(self): + + def test_just_out_capture(self): cap = self.getcapture(out=True, err=False) sys.stdout.write("hello") sys.stderr.write("world") out, err = cap.reset() assert out == "hello" - assert not err + assert not err - def test_just_err_capture(self): - cap = self.getcapture(out=False, err=True) + def test_just_err_capture(self): + cap = self.getcapture(out=False, err=True) sys.stdout.write("hello") sys.stderr.write("world") out, err = cap.reset() assert err == "world" - assert not out + assert not out def test_stdin_restored(self): - old = sys.stdin + old = sys.stdin cap = self.getcapture(in_=True) - newstdin = sys.stdin + newstdin = sys.stdin out, err = cap.reset() assert newstdin != sys.stdin - assert sys.stdin is old + assert sys.stdin is old def test_stdin_nulled_by_default(self): print ("XXX this test may well hang instead of crashing") @@ -293,7 +293,7 @@ class TestStdCapture: sys.stderr.write("error\n") out, err = cap.suspend() assert out == "hello\n" - assert not err + assert not err print ("in between") sys.stderr.write("in between\n") cap.resume() @@ -302,7 +302,7 @@ class TestStdCapture: finally: out, err = cap.reset() assert out == "after\n" - assert not err + assert not err class TestStdCaptureNotNow(TestStdCapture): def getcapture(self, **kw): @@ -311,13 +311,13 @@ class TestStdCaptureNotNow(TestStdCapture): cap.startall() return cap -class TestStdCaptureFD(TestStdCapture): +class TestStdCaptureFD(TestStdCapture): pytestmark = needsdup - def getcapture(self, **kw): + def getcapture(self, **kw): return py.io.StdCaptureFD(**kw) - def test_intermingling(self): + def test_intermingling(self): cap = self.getcapture() oswritebytes(1, "1") sys.stdout.write(str(2)) @@ -328,24 +328,24 @@ class TestStdCaptureFD(TestStdCapture): sys.stderr.flush() oswritebytes(2, "c") out, err = cap.reset() - assert out == "123" - assert err == "abc" + assert out == "123" + assert err == "abc" - def test_callcapture(self): - def func(x, y): + def test_callcapture(self): + def func(x, y): print (x) py.std.sys.stderr.write(str(y)) return 42 - - res, out, err = py.io.StdCaptureFD.call(func, 3, y=4) - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") + + res, out, err = py.io.StdCaptureFD.call(func, 3, y=4) + assert res == 42 + assert out.startswith("3") + assert err.startswith("4") class TestStdCaptureFDNotNow(TestStdCaptureFD): pytestmark = needsdup - def getcapture(self, **kw): + def getcapture(self, **kw): kw['now'] = False cap = py.io.StdCaptureFD(**kw) cap.startall() @@ -381,7 +381,7 @@ class TestStdCaptureFDinvalidFD: assert result.ret == 0 assert result.parseoutcomes()['passed'] == 3 -def test_capture_not_started_but_reset(): +def test_capture_not_started_but_reset(): capsys = py.io.StdCapture(now=False) capsys.done() capsys.done() @@ -389,7 +389,7 @@ def test_capture_not_started_but_reset(): capsys.reset() @needsdup -def test_capture_no_sys(): +def test_capture_no_sys(): capsys = py.io.StdCapture() try: cap = py.io.StdCaptureFD(patchsys=False) @@ -404,22 +404,22 @@ def test_capture_no_sys(): capsys.reset() @needsdup -def test_callcapture_nofd(): - def func(x, y): +def test_callcapture_nofd(): + def func(x, y): oswritebytes(1, "hello") oswritebytes(2, "hello") print (x) sys.stderr.write(str(y)) return 42 - + capfd = py.io.StdCaptureFD(patchsys=False) try: - res, out, err = py.io.StdCapture.call(func, 3, y=4) + res, out, err = py.io.StdCapture.call(func, 3, y=4) finally: capfd.reset() - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") + assert res == 42 + assert out.startswith("3") + assert err.startswith("4") @needsdup @py.test.mark.multi(use=[True, False]) @@ -438,7 +438,7 @@ def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): def test_capturing_and_logging_fundamentals(testdir, method): if method == "StdCaptureFD" and not hasattr(os, 'dup'): py.test.skip("need os.dup") - # here we check a fundamental feature + # here we check a fundamental feature p = testdir.makepyfile(""" import sys, os import py, logging @@ -461,4 +461,4 @@ def test_capturing_and_logging_fundamentals(testdir, method): "suspend2, captured*hello2*WARNING:root:hello3*", ]) assert "atexit" not in result.stderr.str() - + diff --git a/testing/io_/test_saferepr.py b/testing/io_/test_saferepr.py index c2fb91966..b1a651757 100644 --- a/testing/io_/test_saferepr.py +++ b/testing/io_/test_saferepr.py @@ -23,7 +23,7 @@ class TestSafeRepr: s = saferepr(('*'*50, A()), maxsize=25) assert len(s) == 25 assert s[0] == '(' and s[-1] == ')' - + def test_exceptions(self): class BrokenRepr: def __init__(self, ex): @@ -32,7 +32,7 @@ class TestSafeRepr: def __repr__(self): raise self.ex class BrokenReprException(Exception): - __str__ = None + __str__ = None __repr__ = None assert 'Exception' in saferepr(BrokenRepr(Exception("broken"))) s = saferepr(BrokenReprException("really broken")) @@ -55,10 +55,10 @@ class TestSafeRepr: s = saferepr(Function()) except Exception: py.test.fail("saferepr failed for newstyle class") - + def test_builtin_patch_unpatch(monkeypatch): cpy_builtin = py.builtin.builtins - comp = cpy_builtin.compile + comp = cpy_builtin.compile def mycompile(*args, **kwargs): return comp(*args, **kwargs) class Sub(AssertionError): @@ -69,8 +69,8 @@ def test_builtin_patch_unpatch(monkeypatch): assert cpy_builtin.AssertionError != Sub assert cpy_builtin.compile != mycompile py.code.unpatch_builtins() - assert cpy_builtin.AssertionError is Sub - assert cpy_builtin.compile == mycompile + assert cpy_builtin.AssertionError is Sub + assert cpy_builtin.compile == mycompile def test_unicode_handling(): @@ -83,7 +83,7 @@ def test_unicode_handling(): u = unicode(excinfo) def test_unicode_or_repr(): - from py._code.code import unicode_or_repr + from py._code.code import unicode_or_repr assert unicode_or_repr('hello') == "hello" if sys.version_info[0] < 3: s = unicode_or_repr('\xf6\xc4\x85') diff --git a/testing/io_/test_terminalwriter.py b/testing/io_/test_terminalwriter.py index d8e1c0e4a..bc71d6e56 100644 --- a/testing/io_/test_terminalwriter.py +++ b/testing/io_/test_terminalwriter.py @@ -1,6 +1,6 @@ import py import os, sys -from py._io import terminalwriter +from py._io import terminalwriter def test_get_terminal_width(): x = py.io.get_terminal_width @@ -21,7 +21,7 @@ def test_getdimensions(monkeypatch): def test_terminal_width_COLUMNS(monkeypatch): """ Dummy test for get_terminal_width """ - fcntl = py.test.importorskip("fcntl") + fcntl = py.test.importorskip("fcntl") monkeypatch.setattr(fcntl, 'ioctl', lambda *args: int('x')) monkeypatch.setenv('COLUMNS', '42') assert terminalwriter.get_terminal_width() == 42 @@ -30,20 +30,20 @@ def test_terminal_width_COLUMNS(monkeypatch): def test_terminalwriter_defaultwidth_80(monkeypatch): monkeypatch.setattr(terminalwriter, '_getdimensions', lambda: 0/0) monkeypatch.delenv('COLUMNS', raising=False) - tw = py.io.TerminalWriter() + tw = py.io.TerminalWriter() assert tw.fullwidth == 80 def test_terminalwriter_getdimensions_bogus(monkeypatch): monkeypatch.setattr(terminalwriter, '_getdimensions', lambda: (10,10)) monkeypatch.delenv('COLUMNS', raising=False) - tw = py.io.TerminalWriter() + tw = py.io.TerminalWriter() assert tw.fullwidth == 80 def test_terminalwriter_computes_width(monkeypatch): monkeypatch.setattr(terminalwriter, 'get_terminal_width', lambda: 42) - tw = py.io.TerminalWriter() + tw = py.io.TerminalWriter() assert tw.fullwidth == 42 - + def test_terminalwriter_default_instantiation(): tw = py.io.TerminalWriter(stringio=True) assert hasattr(tw, 'stringio') @@ -99,28 +99,28 @@ class TestTerminalWriter: tw.getlines = getlines return tw - def test_line(self, tw): + def test_line(self, tw): tw.line("hello") l = tw.getlines() assert len(l) == 1 assert l[0] == "hello\n" - def test_line_unicode(self, tw): + def test_line_unicode(self, tw): for encoding in 'utf8', 'latin1': - tw._encoding = encoding + tw._encoding = encoding msg = py.builtin._totext('b\u00f6y', 'utf8') tw.line(msg) l = tw.getlines() assert l[0] == msg + "\n" def test_sep_no_title(self, tw): - tw.sep("-", fullwidth=60) + tw.sep("-", fullwidth=60) l = tw.getlines() assert len(l) == 1 assert l[0] == "-" * 60 + "\n" def test_sep_with_title(self, tw): - tw.sep("-", "hello", fullwidth=60) + tw.sep("-", "hello", fullwidth=60) l = tw.getlines() assert len(l) == 1 assert l[0] == "-" * 26 + " hello " + "-" * 27 + "\n" @@ -166,7 +166,7 @@ def test_attr_hasmarkup(): def test_ansi_print(): # we have no easy way to construct a file that - # represents a terminal + # represents a terminal f = py.io.TextIO() f.isatty = lambda: True py.io.ansi_print("hello", 0x32, file=f) diff --git a/testing/log/test_log.py b/testing/log/test_log.py index 5f84afc11..b41bc3a58 100644 --- a/testing/log/test_log.py +++ b/testing/log/test_log.py @@ -5,44 +5,44 @@ from py._log.log import default_keywordmapper callcapture = py.io.StdCapture.call -def setup_module(mod): +def setup_module(mod): mod._oldstate = default_keywordmapper.getstate() -def teardown_module(mod): +def teardown_module(mod): default_keywordmapper.setstate(mod._oldstate) -class TestLogProducer: - def setup_method(self, meth): +class TestLogProducer: + def setup_method(self, meth): default_keywordmapper.setstate(_oldstate) def test_getstate_setstate(self): state = py.log._getstate() py.log.setconsumer("hello", [].append) state2 = py.log._getstate() - assert state2 != state + assert state2 != state py.log._setstate(state) state3 = py.log._getstate() - assert state3 == state + assert state3 == state - def test_producer_repr(self): + def test_producer_repr(self): d = py.log.Producer("default") assert repr(d).find('default') != -1 - def test_produce_one_keyword(self): + def test_produce_one_keyword(self): l = [] - py.log.setconsumer('s1', l.append) - py.log.Producer('s1')("hello world") + py.log.setconsumer('s1', l.append) + py.log.Producer('s1')("hello world") assert len(l) == 1 msg = l[0] - assert msg.content().startswith('hello world') - assert msg.prefix() == '[s1] ' + assert msg.content().startswith('hello world') + assert msg.prefix() == '[s1] ' assert str(msg) == "[s1] hello world" - def test_producer_class(self): - p = py.log.Producer('x1') + def test_producer_class(self): + p = py.log.Producer('x1') l = [] - py.log.setconsumer(p._keywords, l.append) - p("hello") + py.log.setconsumer(p._keywords, l.append) + p("hello") assert len(l) == 1 assert len(l[0].keywords) == 1 assert 'x1' == l[0].keywords[0] @@ -52,25 +52,25 @@ class TestLogProducer: x2 = p.x2 assert x2 is p.x2 -class TestLogConsumer: - def setup_method(self, meth): +class TestLogConsumer: + def setup_method(self, meth): default_keywordmapper.setstate(_oldstate) - def test_log_none(self): + def test_log_none(self): log = py.log.Producer("XXX") l = [] py.log.setconsumer('XXX', l.append) log("1") - assert l + assert l l[:] = [] - py.log.setconsumer('XXX', None) + py.log.setconsumer('XXX', None) log("2") - assert not l + assert not l def test_log_default_stderr(self): res, out, err = callcapture(py.log.Producer("default"), "hello") - assert err.strip() == "[default] hello" + assert err.strip() == "[default] hello" - def test_simple_consumer_match(self): + def test_simple_consumer_match(self): l = [] py.log.setconsumer("x1", l.append) p = py.log.Producer("x1 x2") @@ -78,7 +78,7 @@ class TestLogConsumer: assert l assert l[0].content() == "hello" - def test_simple_consumer_match_2(self): + def test_simple_consumer_match_2(self): l = [] p = py.log.Producer("x1 x2") py.log.setconsumer(p._keywords, l.append) @@ -88,20 +88,20 @@ class TestLogConsumer: def test_no_auto_producer(self): p = py.log.Producer('x') - py.test.raises(AttributeError, "p._x") + py.test.raises(AttributeError, "p._x") py.test.raises(AttributeError, "p.x_y") - def test_setconsumer_with_producer(self): + def test_setconsumer_with_producer(self): l = [] p = py.log.Producer("hello") py.log.setconsumer(p, l.append) p("world") assert str(l[0]) == "[hello] world" - def test_multi_consumer(self): + def test_multi_consumer(self): l = [] py.log.setconsumer("x1", l.append) - py.log.setconsumer("x1 x2", None) + py.log.setconsumer("x1 x2", None) p = py.log.Producer("x1 x2") p("hello") assert not l @@ -110,7 +110,7 @@ class TestLogConsumer: assert l[0].content() == "hello" def test_log_stderr(self): - py.log.setconsumer("xyz", py.log.STDOUT) + py.log.setconsumer("xyz", py.log.STDOUT) res, out, err = callcapture(py.log.Producer("xyz"), "hello") assert not err assert out.strip() == '[xyz] hello' @@ -118,29 +118,29 @@ class TestLogConsumer: def test_log_file(self, tmpdir): customlog = tmpdir.join('log.out') py.log.setconsumer("default", open(str(customlog), 'w', 1)) - py.log.Producer("default")("hello world #1") + py.log.Producer("default")("hello world #1") assert customlog.readlines() == ['[default] hello world #1\n'] py.log.setconsumer("default", py.log.Path(customlog, buffering=False)) - py.log.Producer("default")("hello world #2") - res = customlog.readlines() + py.log.Producer("default")("hello world #2") + res = customlog.readlines() assert res == ['[default] hello world #2\n'] # no append by default! - + def test_log_file_append_mode(self, tmpdir): logfilefn = tmpdir.join('log_append.out') # The append mode is on by default, so we don't need to specify it for File - py.log.setconsumer("default", py.log.Path(logfilefn, append=True, + py.log.setconsumer("default", py.log.Path(logfilefn, append=True, buffering=0)) assert logfilefn.check() - py.log.Producer("default")("hello world #1") - lines = logfilefn.readlines() + py.log.Producer("default")("hello world #1") + lines = logfilefn.readlines() assert lines == ['[default] hello world #1\n'] py.log.setconsumer("default", py.log.Path(logfilefn, append=True, buffering=0)) - py.log.Producer("default")("hello world #1") - lines = logfilefn.readlines() - assert lines == ['[default] hello world #1\n', + py.log.Producer("default")("hello world #1") + lines = logfilefn.readlines() + assert lines == ['[default] hello world #1\n', '[default] hello world #1\n'] def test_log_file_delayed_create(self, tmpdir): @@ -149,22 +149,22 @@ class TestLogConsumer: py.log.setconsumer("default", py.log.Path(logfilefn, delayed_create=True, buffering=0)) assert not logfilefn.check() - py.log.Producer("default")("hello world #1") - lines = logfilefn.readlines() + py.log.Producer("default")("hello world #1") + lines = logfilefn.readlines() assert lines == ['[default] hello world #1\n'] def test_keyword_based_log_files(self, tmpdir): logfiles = [] keywords = 'k1 k2 k3'.split() - for key in keywords: + for key in keywords: path = tmpdir.join(key) py.log.setconsumer(key, py.log.Path(path, buffering=0)) - + py.log.Producer('k1')('1') py.log.Producer('k2')('2') py.log.Producer('k3')('3') - for key in keywords: + for key in keywords: path = tmpdir.join(key) assert path.read().strip() == '[%s] %s' % (key, key[-1]) @@ -172,14 +172,14 @@ class TestLogConsumer: # I manually inspected /var/log/messages and the entries were there def no_test_log_syslog(self): py.log.setconsumer("default", py.log.Syslog()) - py.log.default("hello world #1") + py.log.default("hello world #1") # disabled for now until I figure out how to read entries in the # Event Logs on Windows # I manually inspected the Application Log and the entries were there def no_test_log_winevent(self): py.log.setconsumer("default", py.log.WinEvent()) - py.log.default("hello world #1") + py.log.default("hello world #1") # disabled for now until I figure out how to properly pass the parameters def no_test_log_email(self): @@ -187,4 +187,4 @@ class TestLogConsumer: fromaddr="grig", toaddrs="grig", subject = "py.log email")) - py.log.default("hello world #1") + py.log.default("hello world #1") diff --git a/testing/log/test_warning.py b/testing/log/test_warning.py index 9227e843c..e39562e79 100644 --- a/testing/log/test_warning.py +++ b/testing/log/test_warning.py @@ -67,7 +67,7 @@ def test_function(recwarn): py.builtin.print_("out", out) py.builtin.print_("err", err) assert err.find("x.y.z") != -1 - lno = py.code.getrawcode(test_function).co_firstlineno + lno = py.code.getrawcode(test_function).co_firstlineno exp = "%s:%s" % (mypath, lno) assert err.find(exp) != -1 diff --git a/testing/path/common.py b/testing/path/common.py index 86e7a03e2..802df13ee 100644 --- a/testing/path/common.py +++ b/testing/path/common.py @@ -16,19 +16,19 @@ class CommonFSTests(object): def test_join(self, path1): p = path1.join('sampledir') - strp = str(p) - assert strp.endswith('sampledir') - assert strp.startswith(str(path1)) + strp = str(p) + assert strp.endswith('sampledir') + assert strp.startswith(str(path1)) def test_join_normalized(self, path1): newpath = path1.join(path1.sep+'sampledir') - strp = str(newpath) - assert strp.endswith('sampledir') - assert strp.startswith(str(path1)) + strp = str(newpath) + assert strp.endswith('sampledir') + assert strp.startswith(str(path1)) newpath = path1.join((path1.sep*2) + 'sampledir') - strp = str(newpath) - assert strp.endswith('sampledir') - assert strp.startswith(str(path1)) + strp = str(newpath) + assert strp.endswith('sampledir') + assert strp.startswith(str(path1)) def test_join_noargs(self, path1): newpath = path1.join() @@ -125,7 +125,7 @@ class CommonFSTests(object): s = curdir.bestrelpath(curdir.dirpath().join("sister")) assert s == ".." + sep + "sister" assert curdir.bestrelpath(curdir.dirpath()) == ".." - + assert curdir.bestrelpath("hello") == "hello" def test_relto_not_relative(self, path1): @@ -226,7 +226,7 @@ class CommonFSTests(object): newpath = path1.join('samplefile.py') dirname, purebasename, basename, ext = newpath._getbyspec( 'dirname,purebasename,basename,ext') - assert str(path1).endswith(dirname) # be careful with win32 'drive' + assert str(path1).endswith(dirname) # be careful with win32 'drive' assert purebasename == 'samplefile' assert basename == 'samplefile.py' assert ext == '.py' @@ -280,12 +280,12 @@ class CommonFSTests(object): url = path1.join("samplefile") assert url.mtime() > 0 - def test_relto_wrong_type(self, path1): + def test_relto_wrong_type(self, path1): py.test.raises(TypeError, "path1.relto(42)") def test_visit_filesonly(self, path1): l = [] - for i in path1.visit(lambda x: x.check(file=1)): + for i in path1.visit(lambda x: x.check(file=1)): l.append(i.relto(path1)) assert not "sampledir" in l assert path1.sep.join(["sampledir", "otherfile"]) in l @@ -298,7 +298,7 @@ class CommonFSTests(object): def test_visit_nodotfiles(self, path1): l = [] - for i in path1.visit(lambda x: x.check(dotfile=0)): + for i in path1.visit(lambda x: x.check(dotfile=0)): l.append(i.relto(path1)) assert "sampledir" in l assert path1.sep.join(["sampledir", "otherfile"]) in l @@ -381,11 +381,11 @@ class CommonFSTests(object): assert p.check() def test_move_dir(self, path1): - source = path1.join('sampledir') - dest = path1.join('moveddir') + source = path1.join('sampledir') + dest = path1.join('moveddir') source.move(dest) assert dest.check(dir=1) - assert dest.join('otherfile').check(file=1) + assert dest.join('otherfile').check(file=1) assert not source.join('sampledir').check() def setuptestfs(path): @@ -418,12 +418,12 @@ def setuptestfs(path): module_b = otherdir.ensure('b.py') module_b.write('stuff="got it"\n') module_c = otherdir.ensure('c.py') - module_c.write('''import py; + module_c.write('''import py; import otherdir.a value = otherdir.a.result ''') module_d = otherdir.ensure('d.py') - module_d.write('''import py; + module_d.write('''import py; from otherdir import a value2 = a.result ''') diff --git a/testing/path/conftest.py b/testing/path/conftest.py index 355cf1310..a9711b2ce 100644 --- a/testing/path/conftest.py +++ b/testing/path/conftest.py @@ -13,12 +13,12 @@ def pytest_funcarg__repowc1(request): tmpdir = request.getfuncargvalue("tmpdir") repo, repourl, wc = request.cached_setup( setup=lambda: getrepowc(tmpdir, "path1repo", "path1wc"), - scope="module", + scope="module", ) for x in ('test_remove', 'test_move', 'test_status_deleted'): if request.function.__name__.startswith(x): #print >>sys.stderr, ("saving repo", repo, "for", request.function) - _savedrepowc = save_repowc(repo, wc) + _savedrepowc = save_repowc(repo, wc) request.addfinalizer(lambda: restore_repowc(_savedrepowc)) return repo, repourl, wc @@ -26,7 +26,7 @@ def pytest_funcarg__repowc2(request): tmpdir = request.getfuncargvalue("tmpdir") name = request.function.__name__ repo, url, wc = getrepowc(tmpdir, "%s-repo-2" % name, "%s-wc-2" % name) - return repo, url, wc + return repo, url, wc def getsvnbin(): if svnbin is None: @@ -58,12 +58,12 @@ def getrepowc(tmpdir, reponame='basetestrepo', wcname='wc'): def save_repowc(repo, wc): assert not str(repo).startswith("file://"), repo - assert repo.check() + assert repo.check() savedrepo = repo.dirpath(repo.basename+".1") savedwc = wc.dirpath(wc.basename+".1") - repo.copy(savedrepo) + repo.copy(savedrepo) wc.localpath.copy(savedwc.localpath) - return savedrepo, savedwc + return savedrepo, savedwc def restore_repowc(obj): savedrepo, savedwc = obj diff --git a/testing/path/test_cacheutil.py b/testing/path/test_cacheutil.py index af1d0a937..0b5cd3133 100644 --- a/testing/path/test_cacheutil.py +++ b/testing/path/test_cacheutil.py @@ -1,5 +1,5 @@ import py -from py._path import cacheutil +from py._path import cacheutil class BasicCacheAPITest: cache = None @@ -30,14 +30,14 @@ class TestBuildcostAccess(BasicCacheAPITest): def test_cache_works_somewhat_simple(self, monkeypatch): cache = cacheutil.BuildcostAccessCache() - # the default gettime - # BuildcostAccessCache.build can + # the default gettime + # BuildcostAccessCache.build can # result into time()-time() == 0 which makes the below # test fail randomly. Let's rather use incrementing - # numbers instead. + # numbers instead. l = [0] def counter(): - l[0] = l[0] + 1 + l[0] = l[0] + 1 return l[0] monkeypatch.setattr(cacheutil, 'gettime', counter) for x in range(cache.maxentries): @@ -49,7 +49,7 @@ class TestBuildcostAccess(BasicCacheAPITest): for x in range(halfentries): assert cache.getorbuild(x, None) == x assert cache.getorbuild(x, None) == x - # evict one entry + # evict one entry val = cache.getorbuild(-1, lambda: 42) assert val == 42 # check that recently used ones are still there @@ -65,20 +65,20 @@ class TestAging(BasicCacheAPITest): def test_cache_eviction(self): self.cache.getorbuild(17, lambda: 17) - endtime = py.std.time.time() + self.maxsecs * 10 - while py.std.time.time() < endtime: + endtime = py.std.time.time() + self.maxsecs * 10 + while py.std.time.time() < endtime: try: self.cache._getentry(17) except KeyError: - break - py.std.time.sleep(self.maxsecs*0.3) - else: - py.test.fail("waiting for cache eviction failed") + break + py.std.time.sleep(self.maxsecs*0.3) + else: + py.test.fail("waiting for cache eviction failed") -def test_prune_lowestweight(): - maxsecs = 0.05 +def test_prune_lowestweight(): + maxsecs = 0.05 cache = cacheutil.AgingCache(maxentries=10, maxseconds=maxsecs) - for x in range(cache.maxentries): - cache.getorbuild(x, lambda: x) - py.std.time.sleep(maxsecs*1.1) - cache.getorbuild(cache.maxentries+1, lambda: 42) + for x in range(cache.maxentries): + cache.getorbuild(x, lambda: x) + py.std.time.sleep(maxsecs*1.1) + cache.getorbuild(cache.maxentries+1, lambda: 42) diff --git a/testing/path/test_local.py b/testing/path/test_local.py index a5f8dd84e..e13a4899c 100644 --- a/testing/path/test_local.py +++ b/testing/path/test_local.py @@ -18,7 +18,7 @@ def pytest_funcarg__path1(request): common.setuptestfs(path1) return path1 def teardown(path1): - # post check + # post check assert path1.join("samplefile").check() return request.cached_setup(setup, teardown, scope="session") @@ -62,10 +62,10 @@ class TestLocalPath(common.CommonFSTests): def test_remove_routes_ignore_errors(self, tmpdir, monkeypatch): l = [] - monkeypatch.setattr(py.std.shutil, 'rmtree', + monkeypatch.setattr(py.std.shutil, 'rmtree', lambda *args, **kwargs: l.append(kwargs)) tmpdir.remove() - assert not l[0]['ignore_errors'] + assert not l[0]['ignore_errors'] for val in (True, False): l[:] = [] tmpdir.remove(ignore_errors=val) @@ -191,7 +191,7 @@ class TestLocalPath(common.CommonFSTests): if sys.platform == "win32": py.test.skip("win32: work around needed for path length limit") # see http://codespeak.net/pipermail/py-dev/2008q2/000922.html - + # testing paths > 260 chars (which is Windows' limitation, but # depending on how the paths are used), but > 4096 (which is the # Linux' limitation) - the behaviour of paths with names > 4096 chars @@ -210,7 +210,7 @@ class TestLocalPath(common.CommonFSTests): l = list(tmpdir.visit(lambda x: x.check(file=1))) assert len(l) == 3 # check that breadth comes last - assert l[2] == p3 + assert l[2] == p3 class TestExecutionOnWindows: pytestmark = win32only @@ -233,16 +233,16 @@ class TestExecution: monkeypatch.setenv("PATH", noperm, prepend=":") noperm.chmod(0) assert py.path.local.sysfind('jaksdkasldqwe') is None - + def test_sysfind_absolute(self): x = py.path.local.sysfind('test') assert x.check(file=1) - y = py.path.local.sysfind(str(x)) - assert y.check(file=1) - assert y == x + y = py.path.local.sysfind(str(x)) + assert y.check(file=1) + assert y == x def test_sysfind_multiple(self, tmpdir, monkeypatch): - monkeypatch.setenv('PATH', + monkeypatch.setenv('PATH', "%s:%s" % (tmpdir.ensure('a'), tmpdir.join('b')), prepend=":") @@ -255,9 +255,9 @@ class TestExecution: assert py.path.local.sysfind('a', checker=checker) is None def test_sysexec(self): - x = py.path.local.sysfind('ls') + x = py.path.local.sysfind('ls') out = x.sysexec('-a') - for x in py.path.local().listdir(): + for x in py.path.local().listdir(): assert out.find(x.basename) != -1 def test_sysexec_failing(self): @@ -298,11 +298,11 @@ class TestExecution: # -class TestImport: +class TestImport: def test_pyimport(self, path1): obj = path1.join('execfile.py').pyimport() assert obj.x == 42 - assert obj.__name__ == 'execfile' + assert obj.__name__ == 'execfile' def test_pyimport_dir(self, tmpdir): p = tmpdir.join("hello_123") @@ -313,19 +313,19 @@ class TestImport: def test_pyimport_execfile_different_name(self, path1): obj = path1.join('execfile.py').pyimport(modname="0x.y.z") assert obj.x == 42 - assert obj.__name__ == '0x.y.z' + assert obj.__name__ == '0x.y.z' def test_pyimport_a(self, path1): otherdir = path1.join('otherdir') mod = otherdir.join('a.py').pyimport() assert mod.result == "got it" - assert mod.__name__ == 'otherdir.a' + assert mod.__name__ == 'otherdir.a' def test_pyimport_b(self, path1): otherdir = path1.join('otherdir') mod = otherdir.join('b.py').pyimport() assert mod.stuff == "got it" - assert mod.__name__ == 'otherdir.b' + assert mod.__name__ == 'otherdir.b' def test_pyimport_c(self, path1): otherdir = path1.join('otherdir') @@ -338,11 +338,11 @@ class TestImport: assert mod.value2 == "got it" def test_pyimport_and_import(self, tmpdir): - tmpdir.ensure('xxxpackage', '__init__.py') + tmpdir.ensure('xxxpackage', '__init__.py') mod1path = tmpdir.ensure('xxxpackage', 'module1.py') - mod1 = mod1path.pyimport() - assert mod1.__name__ == 'xxxpackage.module1' - from xxxpackage import module1 + mod1 = mod1path.pyimport() + assert mod1.__name__ == 'xxxpackage.module1' + from xxxpackage import module1 assert module1 is mod1 def test_pyimport_check_filepath_consistency(self, monkeypatch, tmpdir): @@ -361,11 +361,11 @@ class TestImport: pseudopath = tmpdir.ensure(name+"123.py") mod.__file__ = str(pseudopath) monkeypatch.setitem(sys.modules, name, mod) - excinfo = py.test.raises(pseudopath.ImportMismatchError, + excinfo = py.test.raises(pseudopath.ImportMismatchError, "p.pyimport()") modname, modfile, orig = excinfo.value.args assert modname == name - assert modfile == pseudopath + assert modfile == pseudopath assert orig == p assert issubclass(pseudopath.ImportMismatchError, ImportError) @@ -382,7 +382,7 @@ def test_pypkgdir_unimportable(tmpdir): subdir = pkg.ensure("subdir/__init__.py").dirpath() assert subdir.pypkgpath() == subdir assert subdir.ensure("xyz.py").pypkgpath() == subdir - assert not pkg.pypkgpath() + assert not pkg.pypkgpath() def test_isimportable(): from py._path.local import isimportable @@ -402,7 +402,7 @@ def test_homedir(): def test_samefile(tmpdir): assert tmpdir.samefile(tmpdir) p = tmpdir.ensure("hello") - assert p.samefile(p) + assert p.samefile(p) def test_mkdtemp_rootdir(tmpdir): dtmp = local.mkdtemp(rootdir=tmpdir) @@ -433,7 +433,7 @@ class TestWINLocalPath: t2 = path1.join("A_path") assert t1 == t1 assert t1 == t2 - + def test_relto_with_mixed_case(self, path1): t1 = path1.join("a_path", "fiLe") t2 = path1.join("A_path") @@ -455,7 +455,7 @@ class TestWINLocalPath: x = py.path.local.sysfind(cmd.relto(root)) assert x.check(file=1) finally: - old.chdir() + old.chdir() class TestPOSIXLocalPath: pytestmark = skiponwin32 @@ -466,14 +466,14 @@ class TestPOSIXLocalPath: filepath.write("Hello") nlink = filepath.stat().nlink linkpath.mklinkto(filepath) - assert filepath.stat().nlink == nlink + 1 + assert filepath.stat().nlink == nlink + 1 def test_symlink_are_identical(self, tmpdir): filepath = tmpdir.join('file') filepath.write("Hello") linkpath = tmpdir.join('test') linkpath.mksymlinkto(filepath) - assert linkpath.readlink() == str(filepath) + assert linkpath.readlink() == str(filepath) def test_symlink_isfile(self, tmpdir): linkpath = tmpdir.join('test') @@ -531,17 +531,17 @@ class TestPOSIXLocalPath: from pwd import getpwuid from grp import getgrgid stat = path1.stat() - assert stat.path == path1 + assert stat.path == path1 uid = stat.uid gid = stat.gid owner = getpwuid(uid)[0] group = getgrgid(gid)[0] - assert uid == stat.uid - assert owner == stat.owner - assert gid == stat.gid - assert group == stat.group + assert uid == stat.uid + assert owner == stat.owner + assert gid == stat.gid + assert group == stat.group def test_atime(self, tmpdir): import time @@ -549,9 +549,9 @@ class TestPOSIXLocalPath: now = time.time() atime1 = path.atime() # we could wait here but timer resolution is very - # system dependent + # system dependent path.read() - time.sleep(0.01) + time.sleep(0.01) atime2 = path.atime() time.sleep(0.01) duration = time.time() - now @@ -570,17 +570,17 @@ class TestPOSIXLocalPath: # using the subversion command line api. p1 = path1.join('something') p2 = py.path.local(path1.sep+'blabla') - assert p1.common(p2) == '/' + assert p1.common(p2) == '/' - def test_join_to_root(self, path1): + def test_join_to_root(self, path1): root = path1.parts()[0] assert len(str(root)) == 1 assert str(root.join('a')) == '/a' - def test_join_root_to_root_with_no_abs(self, path1): + def test_join_root_to_root_with_no_abs(self, path1): nroot = path1.join('/') - assert str(path1) == str(nroot) - assert path1 == nroot + assert str(path1) == str(nroot) + assert path1 == nroot def test_chmod_simple_int(self, path1): mode = path1.stat().mode diff --git a/testing/path/test_svnauth.py b/testing/path/test_svnauth.py index 27a53c746..704ae33b9 100644 --- a/testing/path/test_svnauth.py +++ b/testing/path/test_svnauth.py @@ -8,7 +8,7 @@ svnbin = py.path.local.sysfind('svn') def make_repo_auth(repo, userdata): """ write config to repo - + user information in userdata is used for auth userdata has user names as keys, and a tuple (password, readwrite) as values, where 'readwrite' is either 'r' or 'rw' @@ -301,7 +301,7 @@ class TestSvnWCAuthFunctional: interactive=False) wc = py.path.svnwc(setup.temppath, auth) py.test.raises(Exception, - ("wc.checkout('svn://localhost:%(port)s/%(repopath)s')" % + ("wc.checkout('svn://localhost:%(port)s/%(repopath)s')" % setup.__dict__)) def test_log(self, setup): diff --git a/testing/path/test_svnurl.py b/testing/path/test_svnurl.py index e3a3e96ab..15fbea504 100644 --- a/testing/path/test_svnurl.py +++ b/testing/path/test_svnurl.py @@ -55,7 +55,7 @@ class TestSvnURLCommandPath(CommonSvnTests): n2 = [x.basename for x in path1.listdir()] n1.sort() n2.sort() - assert n1 == n2 + assert n1 == n2 assert not p.join('.svn').check() rev = path1.mkdir("newdir") tmpdir.remove() diff --git a/testing/path/test_svnwc.py b/testing/path/test_svnwc.py index 82ff8f4c4..fb08f065a 100644 --- a/testing/path/test_svnwc.py +++ b/testing/path/test_svnwc.py @@ -98,11 +98,11 @@ class TestWCSvnCommandPath(CommonSvnTests): s = path1.status(rec=1) # Comparing just the file names, because paths are unpredictable # on Windows. (long vs. 8.3 paths) - assert r.join('samplefile').basename in [item.basename + assert r.join('samplefile').basename in [item.basename for item in s.unchanged] - assert r.join('sampledir').basename in [item.basename + assert r.join('sampledir').basename in [item.basename for item in s.unchanged] - assert r.join('sampledir/otherfile').basename in [item.basename + assert r.join('sampledir/otherfile').basename in [item.basename for item in s.unchanged] def test_status_update(self, path1): @@ -112,7 +112,7 @@ class TestWCSvnCommandPath(CommonSvnTests): s = r.status(updates=1, rec=1) # Comparing just the file names, because paths are unpredictable # on Windows. (long vs. 8.3 paths) - assert r.join('anotherfile').basename in [item.basename for + assert r.join('anotherfile').basename in [item.basename for item in s.update_available] #assert len(s.update_available) == 1 finally: @@ -246,7 +246,7 @@ class TestWCSvnCommandPath(CommonSvnTests): def test_versioned(self, path1): assert path1.check(versioned=1) # TODO: Why does my copy of svn think .svn is versioned? - #assert path1.join('.svn').check(versioned=0) + #assert path1.join('.svn').check(versioned=0) assert path1.join('samplefile').check(versioned=1) assert not path1.join('notexisting').check(versioned=1) notexisting = path1.join('hello').localpath @@ -261,7 +261,7 @@ class TestWCSvnCommandPath(CommonSvnTests): p = path1.localpath.ensure("not_a_versioned_file") l = [x.localpath for x in path1.listdir(lambda x: x.check(versioned=True))] - assert p not in l + assert p not in l def test_nonversioned_remove(self, path1): assert path1.check(versioned=1) @@ -278,7 +278,7 @@ class TestWCSvnCommandPath(CommonSvnTests): assert path1.propget('gaga') == 'this' # Comparing just the file names, because paths are unpredictable # on Windows. (long vs. 8.3 paths) - assert path1.basename in [item.basename for item in + assert path1.basename in [item.basename for item in path1.status().prop_modified] assert 'gaga' in path1.proplist() assert path1.proplist()['gaga'] == 'this' @@ -293,7 +293,7 @@ class TestWCSvnCommandPath(CommonSvnTests): p = path1.proplist(rec=1) # Comparing just the file names, because paths are unpredictable # on Windows. (long vs. 8.3 paths) - assert (path1 / 'samplefile').basename in [item.basename + assert (path1 / 'samplefile').basename in [item.basename for item in p] finally: s.propdel('gugu') @@ -430,7 +430,7 @@ class TestInfoSvnWCCommand: Checksum: 357e44880e5d80157cc5fbc3ce9822e3 """ path = py.path.local(__file__).dirpath().chdir() - try: + try: info = InfoSvnWCCommand(output) finally: path.chdir() diff --git a/testing/plugin/conftest.py b/testing/plugin/conftest.py index f5b34cc56..16af3ca7a 100644 --- a/testing/plugin/conftest.py +++ b/testing/plugin/conftest.py @@ -11,25 +11,25 @@ def pytest_collect_file(path, parent): return mod # for plugin test we try to automatically make sure that -# the according plugin is loaded +# the according plugin is loaded def pytest_funcarg__testdir(request): testdir = request.getfuncargvalue("testdir") #for obj in (request.cls, request.module): - # if hasattr(obj, 'testplugin'): + # if hasattr(obj, 'testplugin'): # testdir.plugins.append(obj.testplugin) # break #else: - modname = request.module.__name__.split(".")[-1] + modname = request.module.__name__.split(".")[-1] if modname.startswith("test_pytest_"): modname = modname[5:] if plugindir.join("%s.py" % modname).check(): if modname[7:] not in default_plugins: testdir.plugins.append(vars(request.module)) - testdir.plugins.append(modname) + testdir.plugins.append(modname) #elif modname.startswith("test_pytest"): # pname = modname[5:] # assert pname not in testdir.plugins - # testdir.plugins.append(pname) + # testdir.plugins.append(pname) # #testdir.plugins.append(vars(request.module)) else: pass # raise ValueError("need better support code") diff --git a/testing/plugin/test_pytest__pytest.py b/testing/plugin/test_pytest__pytest.py index 4dfa6fda0..affc9e094 100644 --- a/testing/plugin/test_pytest__pytest.py +++ b/testing/plugin/test_pytest__pytest.py @@ -11,7 +11,7 @@ def test_hookrecorder_basic(): rec.start_recording(ApiClass) rec.hook.pytest_xyz(arg=123) call = rec.popcall("pytest_xyz") - assert call.arg == 123 + assert call.arg == 123 assert call._name == "pytest_xyz" py.test.raises(ValueError, "rec.popcall('abc')") diff --git a/testing/plugin/test_pytest_assertion.py b/testing/plugin/test_pytest_assertion.py index cb99f7e92..75236658b 100644 --- a/testing/plugin/test_pytest_assertion.py +++ b/testing/plugin/test_pytest_assertion.py @@ -5,9 +5,9 @@ def test_functional(testdir): assert x == 4 """) result = testdir.runpytest() - assert "3 == 4" in result.stdout.str() + assert "3 == 4" in result.stdout.str() result = testdir.runpytest("--no-assert") - assert "3 == 4" not in result.stdout.str() + assert "3 == 4" not in result.stdout.str() def test_traceback_failure(testdir): p1 = testdir.makepyfile(""" @@ -20,9 +20,9 @@ def test_traceback_failure(testdir): """) result = testdir.runpytest(p1) result.stdout.fnmatch_lines([ - "*test_traceback_failure.py F", + "*test_traceback_failure.py F", "====* FAILURES *====", - "____*____", + "____*____", "", " def test_onefails():", "> f(3)", diff --git a/testing/plugin/test_pytest_capture.py b/testing/plugin/test_pytest_capture.py index ee3b17c48..a583bd873 100644 --- a/testing/plugin/test_pytest_capture.py +++ b/testing/plugin/test_pytest_capture.py @@ -10,7 +10,7 @@ class TestCaptureManager: capman = CaptureManager() monkeypatch.delattr(os, 'dup', raising=False) try: - assert capman._getmethod(config, None) == "sys" + assert capman._getmethod(config, None) == "sys" finally: monkeypatch.undo() @@ -20,9 +20,9 @@ class TestCaptureManager: capman = CaptureManager() hasfd = hasattr(os, 'dup') if hasfd: - assert capman._getmethod(config, None) == "fd" + assert capman._getmethod(config, None) == "fd" else: - assert capman._getmethod(config, None) == "sys" + assert capman._getmethod(config, None) == "sys" for name in ('no', 'fd', 'sys'): if not hasfd and name == 'fd': @@ -52,10 +52,10 @@ class TestCaptureManager: assert out == "hello\n" capman.resumecapture(method) out, err = capman.suspendcapture() - assert not out and not err + assert not out and not err finally: capouter.reset() - + @needsosdup def test_juggle_capturings(self, testdir): capouter = py.io.StdCaptureFD() @@ -115,7 +115,7 @@ def test_collect_capturing(testdir): result = testdir.runpytest(p) result.stdout.fnmatch_lines([ "*Captured stdout*", - "*collect 13 failure*", + "*collect 13 failure*", ]) class TestPerTestCapturing: @@ -158,9 +158,9 @@ class TestPerTestCapturing: result = testdir.runpytest(p) result.stdout.fnmatch_lines([ "*test_func():*", - "*Captured stdout during setup*", - "module-setup*", - "function-setup*", + "*Captured stdout during setup*", + "module-setup*", + "function-setup*", "*Captured stdout*", "in teardown*", ]) @@ -176,8 +176,8 @@ class TestPerTestCapturing: """) result = testdir.runpytest(p) s = result.stdout.str() - assert "in func1" not in s - assert "in func2" in s + assert "in func1" not in s + assert "in func2" in s def test_teardown_capturing(self, testdir): @@ -187,7 +187,7 @@ class TestPerTestCapturing: def teardown_function(function): print ("teardown func1") assert 0 - def test_func1(): + def test_func1(): print ("in func1") pass """) @@ -211,15 +211,15 @@ class TestPerTestCapturing: """) result = testdir.runpytest(p) result.stdout.fnmatch_lines([ - "*def teardown_module(mod):*", - "*Captured stdout*", - "*teardown module*", - "*1 error*", + "*def teardown_module(mod):*", + "*Captured stdout*", + "*teardown module*", + "*1 error*", ]) - def test_capturing_outerr(self, testdir): + def test_capturing_outerr(self, testdir): p1 = testdir.makepyfile(""" - import sys + import sys def test_capturing(): print (42) sys.stderr.write(str(23)) @@ -230,9 +230,9 @@ class TestPerTestCapturing: """) result = testdir.runpytest(p1) result.stdout.fnmatch_lines([ - "*test_capturing_outerr.py .F", + "*test_capturing_outerr.py .F", "====* FAILURES *====", - "____*____", + "____*____", "*test_capturing_outerr.py:8: ValueError", "*--- Captured stdout ---*", "1", @@ -252,7 +252,7 @@ class TestLoggingInteraction: """) result = testdir.runpytest(p) result.stderr.str().find("atexit") == -1 - + def test_logging_and_immediate_setupteardown(self, testdir): p = testdir.makepyfile(""" import logging @@ -273,8 +273,8 @@ class TestLoggingInteraction: s = result.stdout.str() result.stdout.fnmatch_lines([ "*WARN*hello3", # errors show first! - "*WARN*hello1", - "*WARN*hello2", + "*WARN*hello1", + "*WARN*hello2", ]) # verify proper termination assert "closed" not in s @@ -299,14 +299,14 @@ class TestLoggingInteraction: s = result.stdout.str() result.stdout.fnmatch_lines([ "*WARN*hello3", # errors come first - "*WARN*hello1", - "*WARN*hello2", + "*WARN*hello1", + "*WARN*hello2", ]) # verify proper termination assert "closed" not in s class TestCaptureFuncarg: - def test_std_functional(self, testdir): + def test_std_functional(self, testdir): reprec = testdir.inline_runsource(""" def test_hello(capsys): print (42) @@ -314,9 +314,9 @@ class TestCaptureFuncarg: assert out.startswith("42") """) reprec.assertoutcome(passed=1) - - @needsosdup - def test_stdfd_functional(self, testdir): + + @needsosdup + def test_stdfd_functional(self, testdir): reprec = testdir.inline_runsource(""" def test_hello(capfd): import os @@ -327,7 +327,7 @@ class TestCaptureFuncarg: """) reprec.assertoutcome(passed=1) - def test_partial_setup_failure(self, testdir): + def test_partial_setup_failure(self, testdir): p = testdir.makepyfile(""" def test_hello(capsys, missingarg): pass @@ -339,7 +339,7 @@ class TestCaptureFuncarg: ]) @needsosdup - def test_keyboardinterrupt_disables_capturing(self, testdir): + def test_keyboardinterrupt_disables_capturing(self, testdir): p = testdir.makepyfile(""" def test_hello(capfd): import os @@ -377,4 +377,4 @@ def test_fdfuncarg_skips_on_no_osdup(testdir): result.stdout.fnmatch_lines([ "*1 skipped*" ]) - + diff --git a/testing/plugin/test_pytest_default.py b/testing/plugin/test_pytest_default.py index ba7bf0eff..b71848871 100644 --- a/testing/plugin/test_pytest_default.py +++ b/testing/plugin/test_pytest_default.py @@ -6,7 +6,7 @@ def test_plugin_specify(testdir): config = py.test.raises(ImportError, """ testdir.parseconfig("-p", "nqweotexistent") """) - #py.test.raises(ImportError, + #py.test.raises(ImportError, # "config.pluginmanager.do_configure(config)" #) diff --git a/testing/plugin/test_pytest_doctest.py b/testing/plugin/test_pytest_doctest.py index 52fc25902..161ddf44f 100644 --- a/testing/plugin/test_pytest_doctest.py +++ b/testing/plugin/test_pytest_doctest.py @@ -3,7 +3,7 @@ from py._plugin.pytest_doctest import DoctestModule, DoctestTextfile pytest_plugins = ["pytest_doctest"] class TestDoctests: - + def test_collect_testtextfile(self, testdir): testdir.maketxtfile(whatever="") checkfile = testdir.maketxtfile(test_something=""" @@ -12,16 +12,16 @@ class TestDoctests: >>> i-1 4 """) - for x in (testdir.tmpdir, checkfile): - #print "checking that %s returns custom items" % (x,) + for x in (testdir.tmpdir, checkfile): + #print "checking that %s returns custom items" % (x,) items, reprec = testdir.inline_genitems(x) assert len(items) == 1 assert isinstance(items[0], DoctestTextfile) def test_collect_module(self, testdir): path = testdir.makepyfile(whatever="#") - for p in (path, testdir.tmpdir): - items, reprec = testdir.inline_genitems(p, + for p in (path, testdir.tmpdir): + items, reprec = testdir.inline_genitems(p, '--doctest-modules') assert len(items) == 1 assert isinstance(items[0], DoctestModule) @@ -47,19 +47,19 @@ class TestDoctests: def test_doctest_unexpected_exception(self, testdir): p = testdir.maketxtfile(""" >>> i = 0 - >>> i = 1 + >>> i = 1 >>> x 2 """) reprec = testdir.inline_run(p) call = reprec.getcall("pytest_runtest_logreport") assert call.report.failed - assert call.report.longrepr - # XXX + assert call.report.longrepr + # XXX #testitem, = items #excinfo = py.test.raises(Failed, "testitem.runtest()") #repr = testitem.repr_failure(excinfo, ("", "")) - #assert repr.reprlocation + #assert repr.reprlocation def test_doctestmodule(self, testdir): p = testdir.makepyfile(""" @@ -71,7 +71,7 @@ class TestDoctests: ''' """) reprec = testdir.inline_run(p, "--doctest-modules") - reprec.assertoutcome(failed=1) + reprec.assertoutcome(failed=1) def test_doctestmodule_external(self, testdir): p = testdir.makepyfile(""" @@ -93,7 +93,7 @@ class TestDoctests: "* 1", "*:5: DocTestFailure" ]) - + def test_txtfile_failing(self, testdir): p = testdir.maketxtfile(""" diff --git a/testing/plugin/test_pytest_helpconfig.py b/testing/plugin/test_pytest_helpconfig.py index b0dc9c612..ed5484853 100644 --- a/testing/plugin/test_pytest_helpconfig.py +++ b/testing/plugin/test_pytest_helpconfig.py @@ -2,7 +2,7 @@ import py, os from py._plugin.pytest_helpconfig import collectattr def test_version(testdir): - assert py.version == py.__version__ + assert py.version == py.__version__ result = testdir.runpytest("--version") assert result.ret == 0 #p = py.path.local(py.__file__).dirpath() @@ -43,7 +43,7 @@ def test_hookvalidation_unknown(testdir): def test_hookvalidation_optional(testdir): testdir.makeconftest(""" import py - @py.test.mark.optionalhook + @py.test.mark.optionalhook def pytest_hello(xyz): pass """) diff --git a/testing/plugin/test_pytest_junitxml.py b/testing/plugin/test_pytest_junitxml.py index a0b97e5d6..fe4479aae 100644 --- a/testing/plugin/test_pytest_junitxml.py +++ b/testing/plugin/test_pytest_junitxml.py @@ -12,7 +12,7 @@ def assert_attr(node, **kwargs): for name, expected in kwargs.items(): anode = node.getAttributeNode(name) assert anode, "node %r has no attribute %r" %(node, name) - val = anode.value + val = anode.value assert val == str(expected) class TestPython: @@ -33,7 +33,7 @@ class TestPython: assert 1 """) result, dom = runandparse(testdir) - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, errors=0, failures=1, skips=3, tests=2) @@ -45,12 +45,12 @@ class TestPython: pass """) result, dom = runandparse(testdir) - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, errors=1, tests=0) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, - classname="test_setup_error.test_setup_error", + assert_attr(tnode, + classname="test_setup_error.test_setup_error", name="test_function") fnode = tnode.getElementsByTagName("error")[0] assert_attr(fnode, message="test setup failure") @@ -63,11 +63,11 @@ class TestPython: assert 0 """) result, dom = runandparse(testdir) - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, failures=1) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, + assert_attr(tnode, classname="test_classname_instance.test_classname_instance.TestClass", name="test_method") @@ -75,7 +75,7 @@ class TestPython: testdir.makeconftest("def pytest_runtest_protocol(): 0 / 0") testdir.makepyfile("def test_function(): pass") result, dom = runandparse(testdir) - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, errors=1, tests=0) tnode = node.getElementsByTagName("testcase")[0] @@ -87,12 +87,12 @@ class TestPython: def test_failure_function(self, testdir): testdir.makepyfile("def test_fail(): raise ValueError(42)") result, dom = runandparse(testdir) - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, failures=1, tests=1) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, - classname="test_failure_function.test_failure_function", + assert_attr(tnode, + classname="test_failure_function.test_failure_function", name="test_fail") fnode = tnode.getElementsByTagName("failure")[0] assert_attr(fnode, message="test failure") @@ -103,42 +103,42 @@ class TestPython: def pytest_generate_tests(metafunc): metafunc.addcall(id="<", funcargs=dict(arg1=42)) metafunc.addcall(id="&", funcargs=dict(arg1=44)) - def test_func(arg1): + def test_func(arg1): assert 0 """) result, dom = runandparse(testdir) - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, failures=2, tests=2) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, - classname="test_failure_escape.test_failure_escape", + assert_attr(tnode, + classname="test_failure_escape.test_failure_escape", name="test_func[<]") tnode = node.getElementsByTagName("testcase")[1] - assert_attr(tnode, - classname="test_failure_escape.test_failure_escape", + assert_attr(tnode, + classname="test_failure_escape.test_failure_escape", name="test_func[&]") def test_junit_prefixing(self, testdir): testdir.makepyfile(""" - def test_func(): + def test_func(): assert 0 class TestHello: def test_hello(self): pass """) result, dom = runandparse(testdir, "--junitprefix=xyz") - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, failures=1, tests=2) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, + assert_attr(tnode, classname="xyz.test_junit_prefixing.test_junit_prefixing", name="test_func") tnode = node.getElementsByTagName("testcase")[1] - assert_attr(tnode, + assert_attr(tnode, classname="xyz.test_junit_prefixing.test_junit_prefixing." - "TestHello", + "TestHello", name="test_hello") def test_xfailure_function(self, testdir): @@ -148,11 +148,11 @@ class TestPython: py.test.xfail("42") """) result, dom = runandparse(testdir) - assert not result.ret + assert not result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, skips=1, tests=0) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, + assert_attr(tnode, classname="test_xfailure_function.test_xfailure_function", name="test_xfail") fnode = tnode.getElementsByTagName("skipped")[0] @@ -167,11 +167,11 @@ class TestPython: pass """) result, dom = runandparse(testdir) - #assert result.ret + #assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, skips=1, tests=0) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, + assert_attr(tnode, classname="test_xfailure_xpass.test_xfailure_xpass", name="test_xpass") fnode = tnode.getElementsByTagName("skipped")[0] @@ -181,11 +181,11 @@ class TestPython: def test_collect_error(self, testdir): testdir.makepyfile("syntax error") result, dom = runandparse(testdir) - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, errors=1, tests=0) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, + assert_attr(tnode, #classname="test_collect_error", name="test_collect_error") fnode = tnode.getElementsByTagName("failure")[0] @@ -195,11 +195,11 @@ class TestPython: def test_collect_skipped(self, testdir): testdir.makepyfile("import py ; py.test.skip('xyz')") result, dom = runandparse(testdir) - assert not result.ret + assert not result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, skips=1, tests=0) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, + assert_attr(tnode, #classname="test_collect_error", name="test_collect_skipped") fnode = tnode.getElementsByTagName("skipped")[0] @@ -237,14 +237,14 @@ class TestNonPython: """) testdir.tmpdir.join("myfile.xyz").write("hello") result, dom = runandparse(testdir) - assert result.ret + assert result.ret node = dom.getElementsByTagName("testsuite")[0] assert_attr(node, errors=0, failures=1, skips=0, tests=1) tnode = node.getElementsByTagName("testcase")[0] - assert_attr(tnode, + assert_attr(tnode, #classname="test_collect_error", name="myfile.xyz") fnode = tnode.getElementsByTagName("failure")[0] assert_attr(fnode, message="test failure") assert "custom item runtest failed" in fnode.toxml() - + diff --git a/testing/plugin/test_pytest_mark.py b/testing/plugin/test_pytest_mark.py index e22ec41ff..7e2b488f3 100644 --- a/testing/plugin/test_pytest_mark.py +++ b/testing/plugin/test_pytest_mark.py @@ -16,7 +16,7 @@ class TestMark: mark = Mark() def f(): pass mark.world(x=3, y=4)(f) - assert f.world + assert f.world assert f.world.x == 3 assert f.world.y == 4 @@ -74,7 +74,7 @@ class TestFunctional: class TestClass: pytestmark = [py.test.mark.hello, py.test.mark.world] def test_func(self): - assert TestClass.test_func.hello + assert TestClass.test_func.hello assert TestClass.test_func.world """) clscol = modcol.collect()[0] @@ -88,7 +88,7 @@ class TestFunctional: pytestmark = [py.test.mark.hello, py.test.mark.world] class TestClass: def test_func(self): - assert TestClass.test_func.hello + assert TestClass.test_func.hello assert TestClass.test_func.world """) clscol = modcol.collect()[0] @@ -104,7 +104,7 @@ class TestFunctional: @py.test.mark.hello class TestClass: def test_func(self): - assert TestClass.test_func.hello + assert TestClass.test_func.hello """) clscol = modcol.collect()[0] item = clscol.collect()[0].collect()[0] @@ -119,7 +119,7 @@ class TestFunctional: class TestClass: pytestmark = py.test.mark.world def test_func(self): - assert TestClass.test_func.hello + assert TestClass.test_func.hello assert TestClass.test_func.world """) clscol = modcol.collect()[0] @@ -162,7 +162,7 @@ class TestFunctional: def pytest_funcarg__arg(request): request.applymarker(py.test.mark.hello) def pytest_terminal_summary(terminalreporter): - l = terminalreporter.stats['passed'] + l = terminalreporter.stats['passed'] terminalreporter._tw.line("keyword: %s" % l[0].keywords) """) testdir.makepyfile(""" diff --git a/testing/plugin/test_pytest_monkeypatch.py b/testing/plugin/test_pytest_monkeypatch.py index 97d57e9c3..c4a4ff77d 100644 --- a/testing/plugin/test_pytest_monkeypatch.py +++ b/testing/plugin/test_pytest_monkeypatch.py @@ -85,7 +85,7 @@ def test_setenv(): def test_delenv(): name = 'xyz1234' - assert name not in os.environ + assert name not in os.environ monkeypatch = MonkeyPatch() py.test.raises(KeyError, "monkeypatch.delenv(%r, raising=True)" % name) monkeypatch.delenv(name, raising=False) @@ -94,7 +94,7 @@ def test_delenv(): try: monkeypatch = MonkeyPatch() monkeypatch.delenv(name) - assert name not in os.environ + assert name not in os.environ monkeypatch.setenv(name, "3") assert os.environ[name] == "3" monkeypatch.undo() @@ -115,7 +115,7 @@ def test_setenv_prepend(): def test_monkeypatch_plugin(testdir): reprec = testdir.inline_runsource(""" - pytest_plugins = 'pytest_monkeypatch', + pytest_plugins = 'pytest_monkeypatch', def test_method(monkeypatch): assert monkeypatch.__class__.__name__ == "MonkeyPatch" """) @@ -131,10 +131,10 @@ def test_syspath_prepend(): assert sys.path[0] == "hello" assert sys.path[1] == "world" monkeypatch.undo() - assert sys.path == old + assert sys.path == old monkeypatch.undo() - assert sys.path == old + assert sys.path == old finally: sys.path[:] = old - + diff --git a/testing/plugin/test_pytest_nose.py b/testing/plugin/test_pytest_nose.py index fea4f0cf8..acc32f277 100644 --- a/testing/plugin/test_pytest_nose.py +++ b/testing/plugin/test_pytest_nose.py @@ -39,7 +39,7 @@ def test_nose_test_generator_fixtures(testdir): called[:] = [] for i in range(0, 5): yield check, i - + def check(i): expect = ['outer_setup'] for x in range(0, i): @@ -48,7 +48,7 @@ def test_nose_test_generator_fixtures(testdir): expect.append('inner_setup') eq_(called, expect) - + test_gen.setup = outer_setup test_gen.teardown = outer_teardown check.setup = inner_setup diff --git a/testing/plugin/test_pytest_pastebin.py b/testing/plugin/test_pytest_pastebin.py index 032f683ca..c3403ed7a 100644 --- a/testing/plugin/test_pytest_pastebin.py +++ b/testing/plugin/test_pytest_pastebin.py @@ -1,14 +1,14 @@ class TestPasting: def pytest_funcarg__pastebinlist(self, request): - mp = request.getfuncargvalue("monkeypatch") + mp = request.getfuncargvalue("monkeypatch") pastebinlist = [] class MockProxy: def newPaste(self, language, code): pastebinlist.append((language, code)) plugin = request.config.pluginmanager.getplugin('pastebin') - mp.setattr(plugin, 'getproxy', MockProxy) - return pastebinlist + mp.setattr(plugin, 'getproxy', MockProxy) + return pastebinlist def test_failed(self, testdir, pastebinlist): testpath = testdir.makepyfile(""" @@ -44,4 +44,4 @@ class TestPasting: s = pastebinlist[0][1] for x in 'test_fail test_skip skipped'.split(): assert s.find(x), (s, x) - + diff --git a/testing/plugin/test_pytest_pdb.py b/testing/plugin/test_pytest_pdb.py index 87a98a504..f3cf001ab 100644 --- a/testing/plugin/test_pytest_pdb.py +++ b/testing/plugin/test_pytest_pdb.py @@ -1,6 +1,6 @@ import py -class TestPDB: +class TestPDB: def pytest_funcarg__pdblist(self, request): monkeypatch = request.getfuncargvalue("monkeypatch") pdblist = [] @@ -8,11 +8,11 @@ class TestPDB: pdblist.append(args) plugin = request.config.pluginmanager.getplugin('pdb') monkeypatch.setattr(plugin, 'post_mortem', mypdb) - return pdblist - + return pdblist + def test_pdb_on_fail(self, testdir, pdblist): rep = testdir.inline_runsource1('--pdb', """ - def test_func(): + def test_func(): assert 0 """) assert rep.failed @@ -24,11 +24,11 @@ class TestPDB: rep = testdir.inline_runsource1('--pdb', """ import py @py.test.mark.xfail - def test_func(): + def test_func(): assert 0 """) assert "xfail" in rep.keywords - assert not pdblist + assert not pdblist def test_pdb_on_skip(self, testdir, pdblist): rep = testdir.inline_runsource1('--pdb', """ @@ -36,7 +36,7 @@ class TestPDB: def test_func(): py.test.skip("hello") """) - assert rep.skipped + assert rep.skipped assert len(pdblist) == 0 def test_pdb_interaction(self, testdir): @@ -52,8 +52,8 @@ class TestPDB: child.sendeof() rest = child.read() assert "1 failed" in rest - assert "def test_1" not in rest - if child.isalive(): + assert "def test_1" not in rest + if child.isalive(): child.wait() def test_pdb_interaction_exception(self, testdir): @@ -72,5 +72,5 @@ class TestPDB: child.expect(".*function") child.sendeof() child.expect("1 failed") - if child.isalive(): + if child.isalive(): child.wait() diff --git a/testing/plugin/test_pytest_pytester.py b/testing/plugin/test_pytest_pytester.py index c4a5ab100..a6a968dfe 100644 --- a/testing/plugin/test_pytest_pytester.py +++ b/testing/plugin/test_pytest_pytester.py @@ -8,9 +8,9 @@ def test_reportrecorder(testdir): class rep: excinfo = None passed = False - failed = True + failed = True skipped = False - when = "call" + when = "call" recorder.hook.pytest_runtest_logreport(report=rep) failures = recorder.getfailures() @@ -23,7 +23,7 @@ def test_reportrecorder(testdir): passed = False failed = False skipped = True - when = "call" + when = "call" rep.passed = False rep.skipped = True recorder.hook.pytest_runtest_logreport(report=rep) @@ -45,7 +45,7 @@ def test_reportrecorder(testdir): assert len(recorder.getfailedcollections()) == 1 recorder.unregister() - recorder.clear() + recorder.clear() recorder.hook.pytest_runtest_logreport(report=rep) py.test.raises(ValueError, "recorder.getfailures()") @@ -58,7 +58,7 @@ def test_parseconfig(testdir): def test_testdir_runs_with_plugin(testdir): testdir.makepyfile(""" - pytest_plugins = "pytest_pytester" + pytest_plugins = "pytest_pytester" def test_hello(testdir): assert 1 """) diff --git a/testing/plugin/test_pytest_recwarn.py b/testing/plugin/test_pytest_recwarn.py index c35b04633..9efe1b8ec 100644 --- a/testing/plugin/test_pytest_recwarn.py +++ b/testing/plugin/test_pytest_recwarn.py @@ -22,7 +22,7 @@ def test_WarningRecorder(recwarn): def test_recwarn_functional(testdir): reprec = testdir.inline_runsource(""" - pytest_plugins = 'pytest_recwarn', + pytest_plugins = 'pytest_recwarn', import warnings oldwarn = warnings.showwarning def test_method(recwarn): @@ -35,7 +35,7 @@ def test_recwarn_functional(testdir): """) res = reprec.countoutcomes() assert tuple(res) == (2, 0, 0), res - + # # ============ test py.test.deprecated_call() ============== # @@ -48,13 +48,13 @@ def dep(i): reg = {} def dep_explicit(i): if i == 0: - py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning, + py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning, filename="hello", lineno=3) def test_deprecated_call_raises(): - excinfo = py.test.raises(AssertionError, + excinfo = py.test.raises(AssertionError, "py.test.deprecated_call(dep, 3)") - assert str(excinfo).find("did not produce") != -1 + assert str(excinfo).find("did not produce") != -1 def test_deprecated_call(): py.test.deprecated_call(dep, 0) @@ -72,7 +72,7 @@ def test_deprecated_call_preserves(): assert f == py.std.warnings.filters def test_deprecated_explicit_call_raises(): - py.test.raises(AssertionError, + py.test.raises(AssertionError, "py.test.deprecated_call(dep_explicit, 3)") def test_deprecated_explicit_call(): diff --git a/testing/plugin/test_pytest_restdoc.py b/testing/plugin/test_pytest_restdoc.py index daf09cf15..cf45f33d0 100644 --- a/testing/plugin/test_pytest_restdoc.py +++ b/testing/plugin/test_pytest_restdoc.py @@ -20,27 +20,27 @@ class TestDoctest: testdir.makepyfile(confrest= "from py._plugin.pytest_restdoc import Project") # we scope our confrest file so that it doesn't - # conflict with another global confrest.py + # conflict with another global confrest.py testdir.makepyfile(__init__="") return testdir - + def test_doctest_extra_exec(self, testdir): xtxt = testdir.maketxtfile(x=""" hello:: - .. >>> raise ValueError + .. >>> raise ValueError >>> None """) result = testdir.runpytest(xtxt) result.stdout.fnmatch_lines(['*1 fail*']) - def test_doctest_basic(self, testdir): + def test_doctest_basic(self, testdir): xtxt = testdir.maketxtfile(x=""" - .. - >>> from os.path import abspath + .. + >>> from os.path import abspath - hello world + hello world - >>> assert abspath + >>> assert abspath >>> i=3 >>> print (i) 3 @@ -57,7 +57,7 @@ class TestDoctest: "*2 passed*" ]) - def test_doctest_eol(self, testdir): + def test_doctest_eol(self, testdir): ytxt = testdir.maketxtfile(y=".. >>> 1 + 1\r\n 2\r\n\r\n") result = testdir.runpytest(ytxt) result.stdout.fnmatch_lines(["*2 passed*"]) @@ -93,4 +93,4 @@ class TestDoctest: outcomes = result.parseoutcomes() assert outcomes['passed'] >= 1 assert 'failed' not in outcomes - assert 'skipped' not in outcomes + assert 'skipped' not in outcomes diff --git a/testing/plugin/test_pytest_resultlog.py b/testing/plugin/test_pytest_resultlog.py index 1585d366d..1ed512140 100644 --- a/testing/plugin/test_pytest_resultlog.py +++ b/testing/plugin/test_pytest_resultlog.py @@ -28,26 +28,26 @@ def test_generic_path(testdir): def test_write_log_entry(): reslog = ResultLog(None, None) reslog.logfile = py.io.TextIO() - reslog.write_log_entry('name', '.', '') + reslog.write_log_entry('name', '.', '') entry = reslog.logfile.getvalue() - assert entry[-1] == '\n' + assert entry[-1] == '\n' entry_lines = entry.splitlines() assert len(entry_lines) == 1 assert entry_lines[0] == '. name' reslog.logfile = py.io.TextIO() - reslog.write_log_entry('name', 's', 'Skipped') + reslog.write_log_entry('name', 's', 'Skipped') entry = reslog.logfile.getvalue() - assert entry[-1] == '\n' + assert entry[-1] == '\n' entry_lines = entry.splitlines() assert len(entry_lines) == 2 assert entry_lines[0] == 's name' assert entry_lines[1] == ' Skipped' reslog.logfile = py.io.TextIO() - reslog.write_log_entry('name', 's', 'Skipped\n') + reslog.write_log_entry('name', 's', 'Skipped\n') entry = reslog.logfile.getvalue() - assert entry[-1] == '\n' + assert entry[-1] == '\n' entry_lines = entry.splitlines() assert len(entry_lines) == 2 assert entry_lines[0] == 's name' @@ -57,29 +57,29 @@ def test_write_log_entry(): longrepr = ' tb1\n tb 2\nE tb3\nSome Error' reslog.write_log_entry('name', 'F', longrepr) entry = reslog.logfile.getvalue() - assert entry[-1] == '\n' + assert entry[-1] == '\n' entry_lines = entry.splitlines() assert len(entry_lines) == 5 assert entry_lines[0] == 'F name' assert entry_lines[1:] == [' '+line for line in longrepr.splitlines()] - + class TestWithFunctionIntegration: # XXX (hpk) i think that the resultlog plugin should - # provide a Parser object so that one can remain - # ignorant regarding formatting details. + # provide a Parser object so that one can remain + # ignorant regarding formatting details. def getresultlog(self, testdir, arg): resultlog = testdir.tmpdir.join("resultlog") testdir.plugins.append("resultlog") args = ["--resultlog=%s" % resultlog] + [arg] testdir.runpytest(*args) return [x for x in resultlog.readlines(cr=0) if x] - + def test_collection_report(self, testdir): ok = testdir.makepyfile(test_collection_ok="") skip = testdir.makepyfile(test_collection_skip="import py ; py.test.skip('hello')") fail = testdir.makepyfile(test_collection_fail="XXX") - lines = self.getresultlog(testdir, ok) + lines = self.getresultlog(testdir, ok) assert not lines lines = self.getresultlog(testdir, skip) @@ -99,7 +99,7 @@ class TestWithFunctionIntegration: def test_log_test_outcomes(self, testdir): mod = testdir.makepyfile(test_mod=""" - import py + import py def test_pass(): pass def test_skip(): py.test.skip("hello") def test_fail(): raise ValueError("FAIL") @@ -107,17 +107,17 @@ class TestWithFunctionIntegration: @py.test.mark.xfail def test_xfail(): raise ValueError("XFAIL") @py.test.mark.xfail - def test_xpass(): pass - + def test_xpass(): pass + """) lines = self.getresultlog(testdir, mod) assert len(lines) >= 3 assert lines[0].startswith(". ") assert lines[0].endswith("test_pass") assert lines[1].startswith("s "), lines[1] - assert lines[1].endswith("test_skip") + assert lines[1].endswith("test_skip") assert lines[2].find("hello") != -1 - + assert lines[3].startswith("F ") assert lines[3].endswith("test_fail") tb = "".join(lines[4:8]) @@ -137,7 +137,7 @@ class TestWithFunctionIntegration: raise ValueError except ValueError: excinfo = py.code.ExceptionInfo() - reslog = ResultLog(None, py.io.TextIO()) + reslog = ResultLog(None, py.io.TextIO()) reslog.pytest_internalerror(excinfo.getrepr()) entry = reslog.logfile.getvalue() entry_lines = entry.splitlines() @@ -145,7 +145,7 @@ class TestWithFunctionIntegration: assert entry_lines[0].startswith('! ') assert os.path.basename(__file__)[:-9] in entry_lines[0] #.pyc/class assert entry_lines[-1][0] == ' ' - assert 'ValueError' in entry + assert 'ValueError' in entry def test_generic(testdir, LineMatcher): testdir.plugins.append("resultlog") @@ -167,11 +167,11 @@ def test_generic(testdir, LineMatcher): testdir.runpytest("--resultlog=result.log") lines = testdir.tmpdir.join("result.log").readlines(cr=0) LineMatcher(lines).fnmatch_lines([ - ". *:test_pass", - "F *:test_fail", + ". *:test_pass", + "F *:test_fail", "s *:test_skip", - "x *:test_xfail", - "x *:test_xfail_norun", + "x *:test_xfail", + "x *:test_xfail_norun", ]) def test_no_resultlog_on_slaves(testdir): diff --git a/testing/plugin/test_pytest_runner.py b/testing/plugin/test_pytest_runner.py index 047f0d2a1..6716af23e 100644 --- a/testing/plugin/test_pytest_runner.py +++ b/testing/plugin/test_pytest_runner.py @@ -11,7 +11,7 @@ class TestSetupState: ss.addfinalizer(l.pop, colitem=item) assert l ss._pop_and_teardown() - assert not l + assert not l def test_setup_scope_None(self, testdir): item = testdir.getitem("def test_func(): pass") @@ -21,11 +21,11 @@ class TestSetupState: ss.addfinalizer(l.pop, colitem=None) assert l ss._pop_and_teardown() - assert l + assert l ss._pop_and_teardown() - assert l + assert l ss.teardown_all() - assert not l + assert not l def test_teardown_exact_stack_empty(self, testdir): item = testdir.getitem("def test_func(): pass") @@ -51,20 +51,20 @@ class BaseFunctionalTests: pass """) rep = reports[1] - assert rep.passed + assert rep.passed assert not rep.failed assert rep.shortrepr == "." assert not hasattr(rep, 'longrepr') - + def test_failfunction(self, testdir): reports = testdir.runitem(""" def test_func(): assert 0 """) rep = reports[1] - assert not rep.passed - assert not rep.skipped - assert rep.failed + assert not rep.passed + assert not rep.skipped + assert rep.failed assert rep.when == "call" assert isinstance(rep.longrepr, ReprExceptionInfo) assert str(rep.shortrepr) == "F" @@ -91,15 +91,15 @@ class BaseFunctionalTests: py.test.skip("hello") """) rep = reports[1] - assert not rep.failed - assert not rep.passed - assert rep.skipped + assert not rep.failed + assert not rep.passed + assert rep.skipped #assert rep.skipped.when == "call" #assert rep.skipped.when == "call" #assert rep.skipped == "%sreason == "hello" #assert rep.skipped.location.lineno == 3 #assert rep.skipped.location.path - #assert not rep.skipped.failurerepr + #assert not rep.skipped.failurerepr def test_skip_in_setup_function(self, testdir): reports = testdir.runitem(""" @@ -111,14 +111,14 @@ class BaseFunctionalTests: """) print(reports) rep = reports[0] - assert not rep.failed - assert not rep.passed - assert rep.skipped + assert not rep.failed + assert not rep.passed + assert rep.skipped #assert rep.skipped.reason == "hello" #assert rep.skipped.location.lineno == 3 #assert rep.skipped.location.lineno == 3 assert len(reports) == 2 - assert reports[1].passed # teardown + assert reports[1].passed # teardown def test_failure_in_setup_function(self, testdir): reports = testdir.runitem(""" @@ -129,9 +129,9 @@ class BaseFunctionalTests: pass """) rep = reports[0] - assert not rep.skipped - assert not rep.passed - assert rep.failed + assert not rep.skipped + assert not rep.passed + assert rep.failed assert rep.when == "setup" assert len(reports) == 2 @@ -146,19 +146,19 @@ class BaseFunctionalTests: print(reports) assert len(reports) == 3 rep = reports[2] - assert not rep.skipped - assert not rep.passed - assert rep.failed - assert rep.when == "teardown" + assert not rep.skipped + assert not rep.passed + assert rep.failed + assert rep.when == "teardown" assert rep.longrepr.reprcrash.lineno == 3 - assert rep.longrepr.reprtraceback.reprentries + assert rep.longrepr.reprtraceback.reprentries def test_custom_failure_repr(self, testdir): testdir.makepyfile(conftest=""" import py class Function(py.test.collect.Function): def repr_failure(self, excinfo): - return "hello" + return "hello" """) reports = testdir.runitem(""" import py @@ -166,12 +166,12 @@ class BaseFunctionalTests: assert 0 """) rep = reports[1] - assert not rep.skipped - assert not rep.passed - assert rep.failed + assert not rep.skipped + assert not rep.passed + assert rep.failed #assert rep.outcome.when == "call" #assert rep.failed.where.lineno == 3 - #assert rep.failed.where.path.basename == "test_func.py" + #assert rep.failed.where.path.basename == "test_func.py" #assert rep.failed.failurerepr == "hello" def test_failure_in_setup_function_ignores_custom_repr(self, testdir): @@ -191,12 +191,12 @@ class BaseFunctionalTests: assert len(reports) == 2 rep = reports[0] print(rep) - assert not rep.skipped - assert not rep.passed - assert rep.failed + assert not rep.skipped + assert not rep.passed + assert rep.failed #assert rep.outcome.when == "setup" #assert rep.outcome.where.lineno == 3 - #assert rep.outcome.where.path.basename == "test_func.py" + #assert rep.outcome.where.path.basename == "test_func.py" #assert instanace(rep.failed.failurerepr, PythonFailureRepr) def test_systemexit_does_not_bail_out(self, testdir): @@ -220,7 +220,7 @@ class BaseFunctionalTests: """) except py.test.exit.Exception: pass - else: + else: py.test.fail("did not raise") class TestExecutionNonForked(BaseFunctionalTests): @@ -237,10 +237,10 @@ class TestExecutionNonForked(BaseFunctionalTests): """) except KeyboardInterrupt: pass - else: + else: py.test.fail("did not raise") -class TestExecutionForked(BaseFunctionalTests): +class TestExecutionForked(BaseFunctionalTests): pytestmark = py.test.mark.skipif("not hasattr(os, 'fork')") def getrunner(self): @@ -269,11 +269,11 @@ class TestCollectionReports: rep = runner.pytest_make_collect_report(col) assert not rep.failed assert not rep.skipped - assert rep.passed - res = rep.result + assert rep.passed + res = rep.result assert len(res) == 2 - assert res[0].name == "test_func1" - assert res[1].name == "TestClass" + assert res[0].name == "test_func1" + assert res[1].name == "TestClass" def test_skip_at_module_scope(self, testdir): col = testdir.getmodulecol(""" @@ -283,22 +283,22 @@ class TestCollectionReports: pass """) rep = runner.pytest_make_collect_report(col) - assert not rep.failed - assert not rep.passed - assert rep.skipped + assert not rep.failed + assert not rep.passed + assert rep.skipped def test_callinfo(): ci = runner.CallInfo(lambda: 0, '123') assert ci.when == "123" assert ci.result == 0 - assert "result" in repr(ci) + assert "result" in repr(ci) ci = runner.CallInfo(lambda: 0/0, '123') assert ci.when == "123" assert not hasattr(ci, 'result') - assert ci.excinfo + assert ci.excinfo assert "exc" in repr(ci) -# design question: do we want general hooks in python files? +# design question: do we want general hooks in python files? # following passes if withpy defaults to True in pycoll.PyObjMix._getplugins() @py.test.mark.xfail def test_runtest_in_module_ordering(testdir): @@ -322,7 +322,7 @@ def test_runtest_in_module_ordering(testdir): def test_hello2(self, mylist): assert mylist == ['class', 'module'], mylist def pytest_runtest_teardown(item): - del item.function.mylist + del item.function.mylist """) result = testdir.runpytest(p1) result.stdout.fnmatch_lines([ @@ -335,10 +335,10 @@ class TestRaises: excinfo = py.test.raises(ValueError, source) code = excinfo.traceback[-1].frame.code s = str(code.fullsource) - assert s == source + assert s == source def test_raises_exec(self): - py.test.raises(ValueError, "a,x = []") + py.test.raises(ValueError, "a,x = []") def test_raises_syntax_error(self): py.test.raises(SyntaxError, "qwe qwe qwe") @@ -415,7 +415,7 @@ def test_importorskip(): assert sys == py.std.sys #path = py.test.importorskip("os.path") #assert path == py.std.os.path - py.test.raises(py.test.skip.Exception, + py.test.raises(py.test.skip.Exception, "py.test.importorskip('alskdj')") py.test.raises(SyntaxError, "py.test.importorskip('x y z')") py.test.raises(SyntaxError, "py.test.importorskip('x=y')") diff --git a/testing/plugin/test_pytest_runner_xunit.py b/testing/plugin/test_pytest_runner_xunit.py index 3b1699ea0..3f23eefb4 100644 --- a/testing/plugin/test_pytest_runner_xunit.py +++ b/testing/plugin/test_pytest_runner_xunit.py @@ -3,7 +3,7 @@ # module, class, and instance level def test_module_and_function_setup(testdir): - reprec = testdir.inline_runsource(""" + reprec = testdir.inline_runsource(""" modlevel = [] def setup_module(module): assert not modlevel @@ -22,15 +22,15 @@ def test_module_and_function_setup(testdir): assert modlevel[0] == 42 assert test_modlevel.answer == 17 - class TestFromClass: + class TestFromClass: def test_module(self): assert modlevel[0] == 42 - assert not hasattr(test_modlevel, 'answer') + assert not hasattr(test_modlevel, 'answer') """) - rep = reprec.matchreport("test_modlevel") - assert rep.passed - rep = reprec.matchreport("test_module") - assert rep.passed + rep = reprec.matchreport("test_modlevel") + assert rep.passed + rep = reprec.matchreport("test_module") + assert rep.passed def test_class_setup(testdir): reprec = testdir.inline_runsource(""" @@ -50,7 +50,7 @@ def test_class_setup(testdir): assert self.clslevel == [23] def test_cleanup(): - assert not TestSimpleClassSetup.clslevel + assert not TestSimpleClassSetup.clslevel assert not TestInheritedClassSetupStillWorks.clslevel """) reprec.assertoutcome(passed=1+2+1) @@ -60,48 +60,48 @@ def test_method_setup(testdir): reprec = testdir.inline_runsource(""" class TestSetupMethod: def setup_method(self, meth): - self.methsetup = meth + self.methsetup = meth def teardown_method(self, meth): - del self.methsetup + del self.methsetup def test_some(self): - assert self.methsetup == self.test_some + assert self.methsetup == self.test_some def test_other(self): assert self.methsetup == self.test_other """) reprec.assertoutcome(passed=2) - + def test_method_generator_setup(testdir): reprec = testdir.inline_runsource(""" - class TestSetupTeardownOnInstance: + class TestSetupTeardownOnInstance: def setup_class(cls): - cls.classsetup = True + cls.classsetup = True def setup_method(self, method): - self.methsetup = method + self.methsetup = method def test_generate(self): - assert self.classsetup - assert self.methsetup == self.test_generate + assert self.classsetup + assert self.methsetup == self.test_generate yield self.generated, 5 yield self.generated, 2 def generated(self, value): - assert self.classsetup - assert self.methsetup == self.test_generate + assert self.classsetup + assert self.methsetup == self.test_generate assert value == 5 """) reprec.assertoutcome(passed=1, failed=1) def test_func_generator_setup(testdir): - reprec = testdir.inline_runsource(""" + reprec = testdir.inline_runsource(""" import sys def setup_module(mod): print ("setup_module") mod.x = [] - + def setup_function(fun): print ("setup_function") x.append(1) @@ -109,22 +109,22 @@ def test_func_generator_setup(testdir): def teardown_function(fun): print ("teardown_function") x.pop() - + def test_one(): assert x == [1] def check(): print ("check") sys.stderr.write("e\\n") assert x == [1] - yield check + yield check assert x == [1] """) - rep = reprec.matchreport("test_one", names="pytest_runtest_logreport") - assert rep.passed - + rep = reprec.matchreport("test_one", names="pytest_runtest_logreport") + assert rep.passed + def test_method_setup_uses_fresh_instances(testdir): reprec = testdir.inline_runsource(""" - class TestSelfState1: + class TestSelfState1: memory = [] def test_hello(self): self.memory.append(self) @@ -154,7 +154,7 @@ def test_setup_that_skips_calledagain_and_teardown(testdir): p = testdir.makepyfile(""" import py def setup_module(mod): - py.test.skip("x") + py.test.skip("x") def test_function1(): pass def test_function2(): diff --git a/testing/plugin/test_pytest_skipping.py b/testing/plugin/test_pytest_skipping.py index 44123b501..7f8f8adb1 100644 --- a/testing/plugin/test_pytest_skipping.py +++ b/testing/plugin/test_pytest_skipping.py @@ -2,7 +2,7 @@ import py from py._plugin.pytest_skipping import MarkEvaluator from py._plugin.pytest_skipping import pytest_runtest_setup -from py._plugin.pytest_runner import runtestprotocol +from py._plugin.pytest_runner import runtestprotocol class TestEvaluator: def test_no_marker(self, testdir): @@ -13,9 +13,9 @@ class TestEvaluator: def test_marked_no_args(self, testdir): item = testdir.getitem(""" - import py + import py @py.test.mark.xyz - def test_func(): + def test_func(): pass """) ev = MarkEvaluator(item, 'xyz') @@ -27,9 +27,9 @@ class TestEvaluator: def test_marked_one_arg(self, testdir): item = testdir.getitem(""" - import py + import py @py.test.mark.xyz("hasattr(os, 'sep')") - def test_func(): + def test_func(): pass """) ev = MarkEvaluator(item, 'xyz') @@ -40,9 +40,9 @@ class TestEvaluator: def test_marked_one_arg_with_reason(self, testdir): item = testdir.getitem(""" - import py + import py @py.test.mark.xyz("hasattr(os, 'sep')", attr=2, reason="hello world") - def test_func(): + def test_func(): pass """) ev = MarkEvaluator(item, 'xyz') @@ -59,10 +59,10 @@ class TestEvaluator: ] for i in range(0, 2): item = testdir.getitem(""" - import py + import py %s %s - def test_func(): + def test_func(): pass """ % (lines[i], lines[(i+1) %2])) ev = MarkEvaluator(item, 'skipif') @@ -73,10 +73,10 @@ class TestEvaluator: def test_marked_one_arg_twice2(self, testdir): item = testdir.getitem(""" - import py + import py @py.test.mark.skipif("hasattr(os, 'murks')") @py.test.mark.skipif("not hasattr(os, 'murks')") - def test_func(): + def test_func(): pass """) ev = MarkEvaluator(item, 'skipif') @@ -103,23 +103,23 @@ class TestEvaluator: class TestXFail: def test_xfail_simple(self, testdir): item = testdir.getitem(""" - import py + import py @py.test.mark.xfail - def test_func(): + def test_func(): assert 0 """) reports = runtestprotocol(item, log=False) assert len(reports) == 3 callreport = reports[1] - assert callreport.skipped + assert callreport.skipped expl = callreport.keywords['xfail'] assert expl == "" def test_xfail_xpassed(self, testdir): item = testdir.getitem(""" - import py + import py @py.test.mark.xfail - def test_func(): + def test_func(): assert 1 """) reports = runtestprotocol(item, log=False) @@ -131,9 +131,9 @@ class TestXFail: def test_xfail_run_anyway(self, testdir): testdir.makepyfile(""" - import py + import py @py.test.mark.xfail - def test_func(): + def test_func(): assert 0 """) result = testdir.runpytest("--runxfail") @@ -153,7 +153,7 @@ class TestXFail: """) reports = runtestprotocol(item, log=False) callreport = reports[1] - assert callreport.failed + assert callreport.failed assert 'xfail' not in callreport.keywords def test_xfail_not_report_default(self, testdir): @@ -242,7 +242,7 @@ class TestXFail: import py def setup_function(function): py.test.xfail("hello") - + def test_this(): assert 0 """) @@ -306,9 +306,9 @@ class TestXFail: class TestSkipif: def test_skipif_conditional(self, testdir): item = testdir.getitem(""" - import py + import py @py.test.mark.skipif("hasattr(os, 'sep')") - def test_func(): + def test_func(): pass """) x = py.test.raises(py.test.skip.Exception, "pytest_runtest_setup(item)") @@ -345,7 +345,7 @@ def test_skip_not_report_default(testdir): def test_skipif_class(testdir): p = testdir.makepyfile(""" import py - + class TestClass: pytestmark = py.test.mark.skipif("True") def test_that(self): @@ -360,7 +360,7 @@ def test_skipif_class(testdir): def test_skip_reasons_folding(): - from py._plugin import pytest_runner as runner + from py._plugin import pytest_runner as runner from py._plugin.pytest_skipping import folded_skips class longrepr: class reprcrash: @@ -371,8 +371,8 @@ def test_skip_reasons_folding(): ev1 = runner.CollectReport(None, None) ev1.when = "execute" ev1.skipped = True - ev1.longrepr = longrepr - + ev1.longrepr = longrepr + ev2 = runner.ItemTestReport(None, excinfo=longrepr) ev2.skipped = True @@ -406,11 +406,11 @@ def test_skipped_reasons_functional(testdir): py.test.skip('test') """ ) - result = testdir.runpytest('--report=skipped') + result = testdir.runpytest('--report=skipped') result.stdout.fnmatch_lines([ "*test_one.py ss", "*test_two.py S", - "*SKIP*3*conftest.py:3: 'test'", + "*SKIP*3*conftest.py:3: 'test'", ]) assert result.ret == 0 diff --git a/testing/plugin/test_pytest_terminal.py b/testing/plugin/test_pytest_terminal.py index 44affcaf0..4eaec2a50 100644 --- a/testing/plugin/test_pytest_terminal.py +++ b/testing/plugin/test_pytest_terminal.py @@ -5,13 +5,13 @@ import py import sys # =============================================================================== -# plugin tests +# plugin tests # # =============================================================================== from py._plugin.pytest_terminal import TerminalReporter, \ CollectonlyReporter, repr_pythonversion, getreportopt -from py._plugin import pytest_runner as runner +from py._plugin import pytest_runner as runner def basic_run_report(item): runner.call_and_report(item, "setup", log=False) @@ -33,11 +33,11 @@ class Option: def pytest_generate_tests(metafunc): if "option" in metafunc.funcargnames: - metafunc.addcall(id="default", + metafunc.addcall(id="default", funcargs={'option': Option(verbose=False)}) - metafunc.addcall(id="verbose", + metafunc.addcall(id="verbose", funcargs={'option': Option(verbose=True)}) - metafunc.addcall(id="fulltrace", + metafunc.addcall(id="fulltrace", funcargs={'option': Option(fulltrace=True)}) @@ -119,7 +119,7 @@ class TestTerminal: import py class Function(py.test.collect.Function): def reportinfo(self): - return "ABCDE", 42, "custom" + return "ABCDE", 42, "custom" """) item = testdir.getitem("def test_func(): pass") tr = TerminalReporter(item.config, file=linecomp.stringio) @@ -135,7 +135,7 @@ class TestTerminal: class Plugin: def pytest_report_iteminfo(self, item): return "FGHJ", 42, "custom" - item.config.pluginmanager.register(Plugin()) + item.config.pluginmanager.register(Plugin()) tr = TerminalReporter(item.config, file=linecomp.stringio) item.config.pluginmanager.register(tr) tr.config.option.verbose = True @@ -150,7 +150,7 @@ class TestTerminal: def test_p1(self): pass class TestClass(BaseTests): - pass + pass """) p2 = testdir.makepyfile(test_p2=""" from test_p1 import BaseTests @@ -182,7 +182,7 @@ class TestTerminal: " def test_foobar():", "> assert 0", "E assert 0", - "*_keyboard_interrupt.py:6: KeyboardInterrupt*", + "*_keyboard_interrupt.py:6: KeyboardInterrupt*", ]) if option.fulltrace: result.stdout.fnmatch_lines([ @@ -208,11 +208,11 @@ class TestCollectonly: item = modcol.join("test_func") rep.config.hook.pytest_itemstart(item=item) linecomp.assert_contains_lines([ - " ", + " ", ]) rep.config.hook.pytest_collectreport( report=runner.CollectReport(modcol, [], excinfo=None)) - assert rep.indent == indent + assert rep.indent == indent def test_collectonly_skipped_module(self, testdir, linecomp): modcol = testdir.getmodulecol(configargs=['--collectonly'], source=""" @@ -244,9 +244,9 @@ class TestCollectonly: def test_collectonly_fatal(self, testdir): p1 = testdir.makeconftest(""" def pytest_collectstart(collector): - assert 0, "urgs" + assert 0, "urgs" """) - result = testdir.runpytest("--collectonly") + result = testdir.runpytest("--collectonly") result.stdout.fnmatch_lines([ "*INTERNAL*args*" ]) @@ -289,7 +289,7 @@ def test_repr_python_version(monkeypatch): monkeypatch.setattr(sys, 'version_info', (2, 5, 1, 'final', 0)) assert repr_pythonversion() == "2.5.1-final-0" py.std.sys.version_info = x = (2,3) - assert repr_pythonversion() == str(x) + assert repr_pythonversion() == str(x) class TestFixtureReporting: def test_setup_fixture_error(self, testdir): @@ -309,7 +309,7 @@ class TestFixtureReporting: "*1 error*", ]) assert result.ret != 0 - + def test_teardown_fixture_error(self, testdir): p = testdir.makepyfile(""" def test_nada(): @@ -320,7 +320,7 @@ class TestFixtureReporting: """) result = testdir.runpytest() result.stdout.fnmatch_lines([ - "*ERROR at teardown*", + "*ERROR at teardown*", "*teardown_function(function):*", "*assert 0*", "*Captured stdout*", @@ -339,13 +339,13 @@ class TestFixtureReporting: """) result = testdir.runpytest() result.stdout.fnmatch_lines([ - "*ERROR at teardown of test_fail*", + "*ERROR at teardown of test_fail*", "*teardown_function(function):*", "*assert False*", "*Captured stdout*", "*teardown func*", - "*test_fail*", + "*test_fail*", "*def test_fail():", "*failingfunc*", "*1 failed*1 error*", @@ -364,8 +364,8 @@ class TestTerminalFunctional: ) result = testdir.runpytest("-k", "test_two:", testpath) result.stdout.fnmatch_lines([ - "*test_deselected.py ..", - "=* 1 test*deselected by 'test_two:'*=", + "*test_deselected.py ..", + "=* 1 test*deselected by 'test_two:'*=", ]) assert result.ret == 0 @@ -379,7 +379,7 @@ class TestTerminalFunctional: def test_skip(): py.test.skip("dontshow") """) - result = testdir.runpytest() + result = testdir.runpytest() assert result.stdout.str().find("skip test summary") == -1 assert result.ret == 1 @@ -397,7 +397,7 @@ class TestTerminalFunctional: finally: old.chdir() result.stdout.fnmatch_lines([ - "test_passes.py ..", + "test_passes.py ..", "* 2 pass*", ]) assert result.ret == 0 @@ -414,19 +414,19 @@ class TestTerminalFunctional: "platform %s -- Python %s*" %( py.std.sys.platform, verinfo), # , py.std.sys.executable), "*test_header_trailer_info.py .", - "=* 1 passed in *.[0-9][0-9] seconds *=", + "=* 1 passed in *.[0-9][0-9] seconds *=", ]) - def test_showlocals(self, testdir): + def test_showlocals(self, testdir): p1 = testdir.makepyfile(""" def test_showlocals(): x = 3 - y = "x" * 5000 + y = "x" * 5000 assert 0 """) result = testdir.runpytest(p1, '-l') result.stdout.fnmatch_lines([ - #"_ _ * Locals *", + #"_ _ * Locals *", "x* = 3", "y* = 'xxxxxx*" ]) @@ -448,7 +448,7 @@ class TestTerminalFunctional: """) result = testdir.runpytest(p1, '-v') result.stdout.fnmatch_lines([ - "*test_verbose_reporting.py:2: test_fail*FAIL*", + "*test_verbose_reporting.py:2: test_fail*FAIL*", "*test_verbose_reporting.py:4: test_pass*PASS*", "*test_verbose_reporting.py:7: TestClass.test_skip*SKIP*", "*test_verbose_reporting.py:10: test_gen*FAIL*", @@ -457,7 +457,7 @@ class TestTerminalFunctional: pytestconfig.pluginmanager.skipifmissing("xdist") result = testdir.runpytest(p1, '-v', '-n 1') result.stdout.fnmatch_lines([ - "*FAIL*test_verbose_reporting.py:2: test_fail*", + "*FAIL*test_verbose_reporting.py:2: test_fail*", ]) assert result.ret == 1 @@ -557,7 +557,7 @@ def test_show_funcarg(testdir, option): ] ) -class TestGenericReporting: +class TestGenericReporting: """ this test class can be subclassed with a different option provider to run e.g. distributed tests. """ @@ -637,7 +637,7 @@ class TestGenericReporting: def test_pytest_report_header(self, testdir, option): testdir.makeconftest(""" def pytest_report_header(config): - return "hello: info" + return "hello: info" """) testdir.mkdir("a").join("conftest.py").write(""" def pytest_report_header(config): diff --git a/testing/plugin/test_pytest_unittest.py b/testing/plugin/test_pytest_unittest.py index e99221efd..4c3c13ec0 100644 --- a/testing/plugin/test_pytest_unittest.py +++ b/testing/plugin/test_pytest_unittest.py @@ -12,7 +12,7 @@ def test_simple_unittest(testdir): """) reprec = testdir.inline_run(testpath) assert reprec.matchreport("testpassing").passed - assert reprec.matchreport("test_failing").failed + assert reprec.matchreport("test_failing").failed def test_isclasscheck_issue53(testdir): testpath = testdir.makepyfile(""" @@ -53,7 +53,7 @@ def test_new_instances(testdir): def test_teardown(testdir): testpath = testdir.makepyfile(""" import unittest - pytest_plugins = "pytest_unittest" # XXX + pytest_plugins = "pytest_unittest" # XXX class MyTestCase(unittest.TestCase): l = [] def test_one(self): diff --git a/testing/process/test_forkedfunc.py b/testing/process/test_forkedfunc.py index f9105d2bd..e6f505586 100644 --- a/testing/process/test_forkedfunc.py +++ b/testing/process/test_forkedfunc.py @@ -29,8 +29,8 @@ def test_exitstatus(): result = py.process.ForkedFunc(func).waitfinish() assert result.exitstatus == 4 assert result.signal == 0 - assert not result.out - assert not result.err + assert not result.out + assert not result.err def test_execption_in_func(): def fun(): @@ -79,7 +79,7 @@ def test_box_in_a_box(): print (result.out) sys.stderr.write(result.err + "\n") return result.retval - + result = py.process.ForkedFunc(boxfun).waitfinish() assert result.out == "someout\n" assert result.err == "someerr\n" @@ -95,7 +95,7 @@ def test_kill_func_forked(): def box_fun(): time.sleep(10) # we don't want to last forever here - + ff = py.process.ForkedFunc(box_fun) os.kill(ff.pid, 15) result = ff.waitfinish() @@ -106,7 +106,7 @@ def test_kill_func_forked(): # ====================================================================== -# examples +# examples # ====================================================================== # @@ -128,7 +128,7 @@ def boxhuge(): os.write(1, s * 10000) os.write(2, s * 10000) os.write(1, s * 10000) - + os.write(1, s * 10000) os.write(2, s * 10000) os.write(2, s * 10000) diff --git a/testing/root/test_builtin.py b/testing/root/test_builtin.py index 76e0b2839..bf659122f 100644 --- a/testing/root/test_builtin.py +++ b/testing/root/test_builtin.py @@ -126,13 +126,13 @@ def test_totext(): py.builtin._totext("hello", "UTF-8") def test_reraise(): - from py.builtin import _reraise + from py.builtin import _reraise try: raise Exception() except Exception: cls, val, tb = sys.exc_info() excinfo = py.test.raises(Exception, "_reraise(cls, val, tb)") - + def test_exec(): l = [] py.builtin.exec_("l.append(1)") diff --git a/testing/root/test_error.py b/testing/root/test_error.py index 1b9cf70ef..e84e70c73 100644 --- a/testing/root/test_error.py +++ b/testing/root/test_error.py @@ -9,10 +9,10 @@ def test_error_classes(): assert issubclass(x, py.error.Error) assert issubclass(x, EnvironmentError) -def test_unknown_error(): +def test_unknown_error(): num = 3999 cls = py.error._geterrnoclass(num) - assert cls.__name__ == 'UnknownErrno%d' % (num,) + assert cls.__name__ == 'UnknownErrno%d' % (num,) assert issubclass(cls, py.error.Error) assert issubclass(cls, EnvironmentError) cls2 = py.error._geterrnoclass(num) @@ -23,7 +23,7 @@ def test_error_conversion_ENOTDIR(testdir): excinfo = py.test.raises(py.error.Error, py.error.checked_call, p.listdir) assert isinstance(excinfo.value, EnvironmentError) assert isinstance(excinfo.value, py.error.Error) - assert "ENOTDIR" in repr(excinfo.value) + assert "ENOTDIR" in repr(excinfo.value) def test_checked_call_supports_kwargs(tmpdir): diff --git a/testing/root/test_oldmagic.py b/testing/root/test_oldmagic.py index f5558d671..9cd365be9 100644 --- a/testing/root/test_oldmagic.py +++ b/testing/root/test_oldmagic.py @@ -26,7 +26,7 @@ def test_invoke_compile(recwarn, monkeypatch): co = compile("def f(): return 1\n", '', 'exec') d = {} py.builtin.exec_(co, d) - assert py.code.Source(d['f']) + assert py.code.Source(d['f']) finally: py.magic.revoke(compile=True) recwarn.pop(DeprecationWarning) @@ -72,7 +72,7 @@ def test_AssertionError(testdir): recwarn.pop(DeprecationWarning) assert err is py.code._AssertionError """) - result = testdir.runpytest() + result = testdir.runpytest() assert "1 passed" in result.stdout.str() def test_autopath_deprecation(testdir): @@ -83,13 +83,13 @@ def test_autopath_deprecation(testdir): recwarn.pop(DeprecationWarning) assert py.path.local(__file__).dirpath() == p.dirpath() """) - result = testdir.runpytest() + result = testdir.runpytest() assert "1 passed" in result.stdout.str() class Testautopath: getauto = "from py.magic import autopath ; autopath = autopath()" - def setup_class(cls): - cls.root = py.test.ensuretemp(cls.__name__) + def setup_class(cls): + cls.root = py.test.ensuretemp(cls.__name__) cls.initdir = cls.root.ensure('pkgdir', dir=1) cls.initdir.ensure('__init__.py') cls.initdir2 = cls.initdir.ensure('initdir2', dir=1) diff --git a/testing/root/test_xmlgen.py b/testing/root/test_xmlgen.py index e566e07e4..50ec07c26 100644 --- a/testing/root/test_xmlgen.py +++ b/testing/root/test_xmlgen.py @@ -2,8 +2,8 @@ import py from py._xmlgen import unicode, html -class ns(py.xml.Namespace): - pass +class ns(py.xml.Namespace): + pass def test_escape(): uvalue = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8') @@ -16,46 +16,46 @@ def test_escape(): return x.encode('utf-8') return x y = py.xml.escape(uvalue) - assert y == uvalue + assert y == uvalue x = py.xml.escape(A()) - assert x == uvalue + assert x == uvalue if py.std.sys.version_info[0] < 3: assert isinstance(x, unicode) assert isinstance(y, unicode) - -def test_tag_with_text(): - x = ns.hello("world") - u = unicode(x) + +def test_tag_with_text(): + x = ns.hello("world") + u = unicode(x) assert u == "world" - -def test_class_identity(): - assert ns.hello is ns.hello -def test_tag_with_text_and_attributes(): - x = ns.some(name="hello", value="world") +def test_class_identity(): + assert ns.hello is ns.hello + +def test_tag_with_text_and_attributes(): + x = ns.some(name="hello", value="world") assert x.attr.name == 'hello' assert x.attr.value == 'world' - u = unicode(x) - assert u == '' + u = unicode(x) + assert u == '' -def test_tag_with_subclassed_attr_simple(): - class my(ns.hello): - class Attr(ns.hello.Attr): - hello="world" - x = my() - assert x.attr.hello == 'world' - assert unicode(x) == '' +def test_tag_with_subclassed_attr_simple(): + class my(ns.hello): + class Attr(ns.hello.Attr): + hello="world" + x = my() + assert x.attr.hello == 'world' + assert unicode(x) == '' -def test_tag_nested(): +def test_tag_nested(): x = ns.hello(ns.world()) unicode(x) # triggers parentifying - assert x[0].parent is x - u = unicode(x) + assert x[0].parent is x + u = unicode(x) assert u == '' -def test_tag_xmlname(): - class my(ns.hello): +def test_tag_xmlname(): + class my(ns.hello): xmlname = 'world' u = unicode(my()) assert u == '' @@ -77,41 +77,41 @@ def test_raw(): assert u == "

literal

" -def test_html_name_stickyness(): - class my(html.p): - pass - x = my("hello") - assert unicode(x) == '

hello

' +def test_html_name_stickyness(): + class my(html.p): + pass + x = my("hello") + assert unicode(x) == '

hello

' -def test_stylenames(): - class my: - class body(html.body): +def test_stylenames(): + class my: + class body(html.body): style = html.Style(font_size = "12pt") u = unicode(my.body()) - assert u == '' + assert u == '' -def test_class_None(): +def test_class_None(): t = html.body(class_=None) - u = unicode(t) + u = unicode(t) assert u == '' -def test_alternating_style(): +def test_alternating_style(): alternating = ( - html.Style(background="white"), + html.Style(background="white"), html.Style(background="grey"), ) - class my(html): - class li(html.li): - def style(self): - i = self.parent.index(self) + class my(html): + class li(html.li): + def style(self): + i = self.parent.index(self) return alternating[i%2] - style = property(style) - + style = property(style) + x = my.ul( - my.li("hello"), - my.li("world"), + my.li("hello"), + my.li("world"), my.li("42")) - u = unicode(x) + u = unicode(x) assert u == ('
  • hello
  • ' '
  • world
  • ' '
  • 42
  • ' @@ -120,7 +120,7 @@ def test_alternating_style(): def test_singleton(): h = html.head(html.link(href="foo")) assert unicode(h) == '' - + h = html.head(html.script(src="foo")) assert unicode(h) == '' diff --git a/testing/test_collect.py b/testing/test_collect.py index 56a35fd0d..300c1ad62 100644 --- a/testing/test_collect.py +++ b/testing/test_collect.py @@ -20,11 +20,11 @@ class TestCollector: assert fn1 != modcol if py.std.sys.version_info < (3, 0): assert cmp(fn1, fn2) == 0 - assert hash(fn1) == hash(fn2) + assert hash(fn1) == hash(fn2) fn3 = modcol.collect_by_name("test_fail") assert isinstance(fn3, py.test.collect.Function) - assert not (fn1 == fn3) + assert not (fn1 == fn3) assert fn1 != fn3 for fn in fn1,fn2,fn3: @@ -42,7 +42,7 @@ class TestCollector: """) cls = modcol.collect_by_name("TestClass") fn = cls.collect_by_name("()").collect_by_name("test_foo") - + parent = fn.getparent(py.test.collect.Module) assert parent is modcol @@ -50,7 +50,7 @@ class TestCollector: assert parent is fn parent = fn.getparent(py.test.collect.Class) - assert parent is cls + assert parent is cls def test_getcustomfile_roundtrip(self, testdir): @@ -74,7 +74,7 @@ class TestCollector: assert isinstance(node, py.test.collect.File) class TestCollectFS: - def test_ignored_certain_directories(self, testdir): + def test_ignored_certain_directories(self, testdir): tmpdir = testdir.tmpdir tmpdir.ensure("_darcs", 'test_notfound.py') tmpdir.ensure("CVS", 'test_notfound.py') @@ -91,7 +91,7 @@ class TestCollectFS: assert 'normal' in names assert 'test_found.py' in names - def test_found_certain_testfiles(self, testdir): + def test_found_certain_testfiles(self, testdir): p1 = testdir.makepyfile(test_found = "pass", found_test="pass") col = testdir.parseconfig(p1).getnode(p1.dirpath()) items = col.collect() # Directory collect returns files sorted by name @@ -139,7 +139,7 @@ class TestCollectPluginHookRelay: reprec = testdir.inline_run() assert "hello" in wascalled assert "world" in wascalled - # make sure the directories do not get double-appended + # make sure the directories do not get double-appended colreports = reprec.getreports("pytest_collectreport") names = [rep.collector.name for rep in colreports] assert names.count("hello") == 1 @@ -228,12 +228,12 @@ class TestCustomConftests: testdir.makepyfile(test_world="#") reprec = testdir.inline_run(testdir.tmpdir) names = [rep.collector.name for rep in reprec.getreports("pytest_collectreport")] - assert 'hello' not in names - assert 'test_world.py' not in names + assert 'hello' not in names + assert 'test_world.py' not in names reprec = testdir.inline_run(testdir.tmpdir, "--XX") names = [rep.collector.name for rep in reprec.getreports("pytest_collectreport")] - assert 'hello' in names - assert 'test_world.py' in names + assert 'hello' in names + assert 'test_world.py' in names def test_pytest_fs_collect_hooks_are_seen(self, testdir): testdir.makeconftest(""" @@ -264,8 +264,8 @@ class TestRootCol: col = config.getnode(x) trail = config._rootcol.totrail(col) col2 = config._rootcol.fromtrail(trail) - assert col2 == col - + assert col2 == col + def test_totrail_topdir_and_beyond(self, testdir, tmpdir): config = testdir.reparseconfig() col = config.getnode(config.topdir) @@ -275,9 +275,9 @@ class TestRootCol: assert len(col2.listchain()) == 1 py.test.raises(config.Error, "config.getnode(config.topdir.dirpath())") #col3 = config.getnode(config.topdir.dirpath()) - #py.test.raises(ValueError, + #py.test.raises(ValueError, # "col3._totrail()") - + def test_argid(self, testdir, tmpdir): cfg = testdir.parseconfig() p = testdir.makepyfile("def test_func(): pass") diff --git a/testing/test_config.py b/testing/test_config.py index 69a1f7e24..c80aae237 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -27,7 +27,7 @@ class TestConfigCmdlineParsing: import os testdir.makeconftest("option_verbose=True") config = testdir.parseconfig() - assert config.option.verbose + assert config.option.verbose def test_parsing_again_fails(self, testdir): config = testdir.reparseconfig([testdir.tmpdir]) @@ -58,7 +58,7 @@ class TestConfigTmpdir: assert not config2.getbasetemp().relto(config3.getbasetemp()) assert not config3.getbasetemp().relto(config2.getbasetemp()) -class TestConfigAPI: +class TestConfigAPI: def test_config_getvalue_honours_conftest(self, testdir): testdir.makepyfile(conftest="x=1") @@ -76,12 +76,12 @@ class TestConfigAPI: def test_config_getvalueorskip(self, testdir): config = testdir.parseconfig() - py.test.raises(py.test.skip.Exception, + py.test.raises(py.test.skip.Exception, "config.getvalueorskip('hello')") verbose = config.getvalueorskip("verbose") assert verbose == config.option.verbose config.option.hello = None - py.test.raises(py.test.skip.Exception, + py.test.raises(py.test.skip.Exception, "config.getvalueorskip('hello')") def test_config_overwrite(self, testdir): @@ -108,9 +108,9 @@ class TestConfigAPI: def test_setsessionclass_and_initsession(self, testdir): config = testdir.Config() - class Session1: + class Session1: def __init__(self, config): - self.config = config + self.config = config config.setsessionclass(Session1) session = config.initsession() assert isinstance(session, Session1) @@ -126,27 +126,27 @@ class TestConfigApi_getinitialnodes: col = colitems[0] assert isinstance(col, py.test.collect.Directory) for col in col.listchain(): - assert col.config is config + assert col.config is config def test_twodirs(self, testdir, tmpdir): config = testdir.reparseconfig([tmpdir, tmpdir]) colitems = config.getinitialnodes() assert len(colitems) == 2 - col1, col2 = colitems - assert col1.name == col2.name - assert col1.parent == col2.parent + col1, col2 = colitems + assert col1.name == col2.name + assert col1.parent == col2.parent def test_curdir_and_subdir(self, testdir, tmpdir): a = tmpdir.ensure("a", dir=1) config = testdir.reparseconfig([tmpdir, a]) colitems = config.getinitialnodes() assert len(colitems) == 2 - col1, col2 = colitems + col1, col2 = colitems assert col1.name == tmpdir.basename assert col2.name == 'a' for col in colitems: for subcol in col.listchain(): - assert col.config is config + assert col.config is config def test_global_file(self, testdir, tmpdir): x = tmpdir.ensure("x.py") @@ -154,10 +154,10 @@ class TestConfigApi_getinitialnodes: col, = config.getinitialnodes() assert isinstance(col, py.test.collect.Module) assert col.name == 'x.py' - assert col.parent.name == tmpdir.basename + assert col.parent.name == tmpdir.basename assert isinstance(col.parent.parent, RootCollector) for col in col.listchain(): - assert col.config is config + assert col.config is config def test_global_dir(self, testdir, tmpdir): x = tmpdir.ensure("a", dir=1) @@ -167,7 +167,7 @@ class TestConfigApi_getinitialnodes: print(col.listchain()) assert col.name == 'a' assert isinstance(col.parent, RootCollector) - assert col.config is config + assert col.config is config def test_pkgfile(self, testdir, tmpdir): tmpdir = tmpdir.join("subdir") @@ -177,10 +177,10 @@ class TestConfigApi_getinitialnodes: col, = config.getinitialnodes() assert isinstance(col, py.test.collect.Module) assert col.name == 'x.py' - assert col.parent.name == x.dirpath().basename + assert col.parent.name == x.dirpath().basename assert isinstance(col.parent.parent.parent, RootCollector) for col in col.listchain(): - assert col.config is config + assert col.config is config class TestConfig_gettopdir: def test_gettopdir(self, testdir): @@ -188,7 +188,7 @@ class TestConfig_gettopdir: tmp = testdir.tmpdir assert gettopdir([tmp]) == tmp topdir = gettopdir([tmp.join("hello"), tmp.join("world")]) - assert topdir == tmp + assert topdir == tmp somefile = tmp.ensure("somefile.py") assert gettopdir([somefile]) == tmp @@ -200,7 +200,7 @@ class TestConfig_gettopdir: c = tmp.ensure('a', 'b', 'c.py') Z = tmp.ensure('Z', dir=1) assert gettopdir([c]) == a - assert gettopdir([c, Z]) == tmp + assert gettopdir([c, Z]) == tmp assert gettopdir(["%s::xyc" % c]) == a assert gettopdir(["%s::xyc::abc" % c]) == a assert gettopdir(["%s::xyc" % c, "%s::abc" % Z]) == tmp @@ -209,24 +209,24 @@ def test_options_on_small_file_do_not_blow_up(testdir): def runfiletest(opts): reprec = testdir.inline_run(*opts) passed, skipped, failed = reprec.countoutcomes() - assert failed == 2 + assert failed == 2 assert skipped == passed == 0 path = testdir.makepyfile(""" def test_f1(): assert 0 def test_f2(): assert 0 """) - for opts in ([], ['-l'], ['-s'], ['--tb=no'], ['--tb=short'], - ['--tb=long'], ['--fulltrace'], ['--nomagic'], + for opts in ([], ['-l'], ['-s'], ['--tb=no'], ['--tb=short'], + ['--tb=long'], ['--fulltrace'], ['--nomagic'], ['--traceconfig'], ['-v'], ['-v', '-v']): runfiletest(opts + [path]) def test_ensuretemp(recwarn): #py.test.deprecated_call(py.test.ensuretemp, 'hello') - d1 = py.test.ensuretemp('hello') - d2 = py.test.ensuretemp('hello') + d1 = py.test.ensuretemp('hello') + d2 = py.test.ensuretemp('hello') assert d1 == d2 - assert d1.check(dir=1) + assert d1.check(dir=1) def test_preparse_ordering(testdir, monkeypatch): pkg_resources = py.test.importorskip("pkg_resources") @@ -252,7 +252,7 @@ def test_preparse_ordering(testdir, monkeypatch): import pickle class TestConfigPickling: def pytest_funcarg__testdir(self, request): - oldconfig = py.test.config + oldconfig = py.test.config print("setting py.test.config to None") py.test.config = None def resetglobals(): @@ -271,9 +271,9 @@ class TestConfigPickling: config2 = Config() config2.__setstate__(config1.__getstate__()) assert config2.topdir == py.path.local() - config2_relpaths = [py.path.local(x).relto(config2.topdir) + config2_relpaths = [py.path.local(x).relto(config2.topdir) for x in config2.args] - config1_relpaths = [py.path.local(x).relto(config1.topdir) + config1_relpaths = [py.path.local(x).relto(config1.topdir) for x in config1.args] assert config2_relpaths == config1_relpaths @@ -285,7 +285,7 @@ class TestConfigPickling: testdir.makeconftest(""" def pytest_addoption(parser): group = parser.getgroup("testing group") - group.addoption('-G', '--glong', action="store", default=42, + group.addoption('-G', '--glong', action="store", default=42, type="int", dest="gdest", help="g value.") """) config = testdir.parseconfig("-G", "11") @@ -296,7 +296,7 @@ class TestConfigPickling: py.test.raises(AttributeError, "config.option.gdest") config2 = testdir.Config() - config2.__setstate__(repr) + config2.__setstate__(repr) assert config2.option.gdest == 11 def test_config_pickling_and_conftest_deprecated(self, testdir): @@ -305,7 +305,7 @@ class TestConfigPickling: tmp.join("conftest.py").write(py.code.Source(""" def pytest_addoption(parser): group = parser.getgroup("testing group") - group.addoption('-G', '--glong', action="store", default=42, + group.addoption('-G', '--glong', action="store", default=42, type="int", dest="gdest", help="g value.") """)) config = testdir.parseconfig(tmp, "-G", "11") @@ -316,10 +316,10 @@ class TestConfigPickling: py.test.raises(AttributeError, "config.option.gdest") config2 = testdir.Config() - config2.__setstate__(repr) + config2.__setstate__(repr) assert config2.option.gdest == 11 - - option = config2.addoptions("testing group", + + option = config2.addoptions("testing group", config2.Option('-G', '--glong', action="store", default=42, type="int", dest="gdest", help="g value.")) assert option.gdest == 11 @@ -340,10 +340,10 @@ class TestConfigPickling: io = py.io.BytesIO() pickler = pickle.Pickler(io) pickler.dump(col) - io.seek(0) + io.seek(0) unpickler = pickle.Unpickler(io) col2 = unpickler.load() - assert col2.name == col.name + assert col2.name == col.name assert col2.listnames() == col.listnames() def test_config_and_collector_pickling(self, testdir): @@ -353,13 +353,13 @@ class TestConfigPickling: assert config.topdir == tmpdir col = config.getnode(dir1.dirpath()) col1 = config.getnode(dir1) - assert col1.parent == col + assert col1.parent == col io = py.io.BytesIO() pickler = pickle.Pickler(io) pickler.dump(col) pickler.dump(col1) pickler.dump(col) - io.seek(0) + io.seek(0) unpickler = pickle.Unpickler(io) newtopdir = tmpdir.ensure("newtopdir", dir=1) newtopdir.mkdir("sourcedir").mkdir("somedir") @@ -369,11 +369,11 @@ class TestConfigPickling: newcol2 = unpickler.load() newcol3 = unpickler.load() assert newcol2.config is newcol.config - assert newcol2.parent == newcol + assert newcol2.parent == newcol assert newcol2.config.topdir.realpath() == newtopdir.realpath() newsourcedir = newtopdir.join("sourcedir") assert newcol.fspath.realpath() == newsourcedir.realpath() assert newcol2.fspath.basename == dir1.basename assert newcol2.fspath.relto(newcol2.config.topdir) finally: - old.chdir() + old.chdir() diff --git a/testing/test_conftesthandle.py b/testing/test_conftesthandle.py index b017835b8..a0fb6a42c 100644 --- a/testing/test_conftesthandle.py +++ b/testing/test_conftesthandle.py @@ -3,18 +3,18 @@ from py._test.conftesthandle import Conftest def pytest_generate_tests(metafunc): if "basedir" in metafunc.funcargnames: - metafunc.addcall(param="global") + metafunc.addcall(param="global") metafunc.addcall(param="inpackage") -def pytest_funcarg__basedir(request): +def pytest_funcarg__basedir(request): def basedirmaker(request): basedir = d = request.getfuncargvalue("tmpdir") d.ensure("adir/conftest.py").write("a=1 ; Directory = 3") d.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5") - if request.param == "inpackage": + if request.param == "inpackage": d.ensure("adir/__init__.py") d.ensure("adir/b/__init__.py") - return d + return d return request.cached_setup(lambda: basedirmaker(request), extrakey=request.param) def ConftestWithSetinitial(path): @@ -31,9 +31,9 @@ class TestConftestValueAccessGlobal: def test_onimport(self, basedir): l = [] conftest = Conftest(onimport=l.append) - conftest.setinitial([basedir.join("adir"), + conftest.setinitial([basedir.join("adir"), '--confcutdir=%s' % basedir]) - assert len(l) == 2 + assert len(l) == 2 assert conftest.rget("a") == 1 assert conftest.rget("b", basedir.join("adir", "b")) == 2 assert len(l) == 2 @@ -52,8 +52,8 @@ class TestConftestValueAccessGlobal: def test_default_has_lower_prio(self, basedir): conftest = ConftestWithSetinitial(basedir.join("adir")) assert conftest.rget('Directory') == 3 - #assert conftest.lget('Directory') == py.test.collect.Directory - + #assert conftest.lget('Directory') == py.test.collect.Directory + def test_value_access_not_existing(self, basedir): conftest = ConftestWithSetinitial(basedir) py.test.raises(KeyError, "conftest.rget('a')") @@ -63,10 +63,10 @@ class TestConftestValueAccessGlobal: conftest = ConftestWithSetinitial(basedir) assert conftest.rget("a", basedir.join('adir')) == 1 #assert conftest.lget("a", basedir.join('adir')) == 1 - assert conftest.rget("a", basedir.join('adir', 'b')) == 1.5 + assert conftest.rget("a", basedir.join('adir', 'b')) == 1.5 #assert conftest.lget("a", basedir.join('adir', 'b')) == 1 #assert conftest.lget("b", basedir.join('adir', 'b')) == 2 - #assert py.test.raises(KeyError, + #assert py.test.raises(KeyError, # 'conftest.lget("b", basedir.join("a"))' #) @@ -116,7 +116,7 @@ def test_conftestcutdir(testdir): l = conftest.getconftestmodules(conf.dirpath()) assert len(l) == 0 assert conf not in conftest._conftestpath2mod - # but we can still import a conftest directly + # but we can still import a conftest directly conftest.importconftest(conf) l = conftest.getconftestmodules(conf.dirpath()) assert l[0].__file__.startswith(str(conf)) diff --git a/testing/test_deprecated_api.py b/testing/test_deprecated_api.py index 2aa29b8ef..4f4757132 100644 --- a/testing/test_deprecated_api.py +++ b/testing/test_deprecated_api.py @@ -2,7 +2,7 @@ import py class TestCollectDeprecated: - + def test_collect_with_deprecated_run_and_join(self, testdir, recwarn): testdir.makeconftest(""" import py @@ -28,7 +28,7 @@ class TestCollectDeprecated: return self.Function(name, parent=self) if name == 'Cls': return MyClass(name, parent=self) - + class MyDirectory(py.test.collect.Directory): Module = MyModule def run(self): @@ -38,7 +38,7 @@ class TestCollectDeprecated: return self.Module(self.fspath.join(name), parent=self) def pytest_collect_directory(path, parent): - if path.basename == "subconf": + if path.basename == "subconf": return MyDirectory(path, parent) """) subconf = testdir.mkpydir("subconf") @@ -46,7 +46,7 @@ class TestCollectDeprecated: somefile.write(py.code.Source(""" def check(): pass class Cls: - def check2(self): pass + def check2(self): pass """)) config = testdir.parseconfig(somefile) dirnode = config.getnode(somefile.dirpath()) @@ -63,12 +63,12 @@ class TestCollectDeprecated: assert len(colitems) == 2 assert colitems[0].name == 'check' assert colitems[1].name == 'Cls' - clscol = colitems[1] + clscol = colitems[1] colitems = clscol.collect() recwarn.pop(DeprecationWarning) assert len(colitems) == 1 - icol = colitems[0] + icol = colitems[0] colitems = icol.collect() recwarn.pop(DeprecationWarning) assert len(colitems) == 1 @@ -94,7 +94,7 @@ class TestCollectDeprecated: class SomeClass: pass """) colitems = col.collect() - recwarn.pop(DeprecationWarning) + recwarn.pop(DeprecationWarning) assert len(colitems) == 1 funcitem = colitems[0] assert funcitem.name == "check_one" @@ -120,7 +120,7 @@ class TestCollectDeprecated: class MyFunction(py.test.collect.Function): def execute(self, obj, *args): pass - Function=MyFunction + Function=MyFunction """) modcol = testdir.getmodulecol("def test_func2(): pass") funcitem = modcol.collect()[0] @@ -142,7 +142,7 @@ class TestCollectDeprecated: modcol = testdir.getmodulecol("def test_some2(): pass") funcitem = modcol.collect()[0] w = recwarn.pop(DeprecationWarning) - assert "conftest.py" in str(w.message) + assert "conftest.py" in str(w.message) recwarn.clear() funcitem._deprecated_testexecution() @@ -177,7 +177,7 @@ class TestCollectDeprecated: assert col.collect() == [] - + class TestDisabled: def test_disabled_module(self, recwarn, testdir): modcol = testdir.getmodulecol(""" @@ -239,7 +239,7 @@ class TestDisabled: elif name in ("Module", "File"): config.getnode(p) else: - fnode = config.getnode(p) + fnode = config.getnode(p) recwarn.clear() fnode.collect() w = recwarn.pop(DeprecationWarning) @@ -251,9 +251,9 @@ def test_config_cmdline_options(recwarn, testdir): def _callback(option, opt_str, value, parser, *args, **kwargs): option.tdest = True Option = py.test.config.Option - option = py.test.config.addoptions("testing group", + option = py.test.config.addoptions("testing group", Option('-G', '--glong', action="store", default=42, - type="int", dest="gdest", help="g value."), + type="int", dest="gdest", help="g value."), # XXX note: special case, option without a destination Option('-T', '--tlong', action="callback", callback=_callback, help='t value'), @@ -262,12 +262,12 @@ def test_config_cmdline_options(recwarn, testdir): recwarn.clear() config = testdir.reparseconfig(['-G', '17']) recwarn.pop(DeprecationWarning) - assert config.option.gdest == 17 + assert config.option.gdest == 17 def test_conftest_non_python_items(recwarn, testdir): testdir.makepyfile(conftest=""" import py - class CustomItem(py.test.collect.Item): + class CustomItem(py.test.collect.Item): def run(self): pass class Directory(py.test.collect.Directory): @@ -302,15 +302,15 @@ def test_extra_python_files_and_functions(testdir, recwarn): if path.check(fnmatch="check_*.py"): return self.Module(path, parent=self) return super(Directory, self).consider_file(path) - class myfuncmixin: + class myfuncmixin: Function = MyFunction - def funcnamefilter(self, name): - return name.startswith('check_') + def funcnamefilter(self, name): + return name.startswith('check_') class Module(myfuncmixin, py.test.collect.Module): - def classnamefilter(self, name): - return name.startswith('CustomTestClass') + def classnamefilter(self, name): + return name.startswith('CustomTestClass') class Instance(myfuncmixin, py.test.collect.Instance): - pass + pass """) checkfile = testdir.makepyfile(check_file=""" def check_func(): @@ -319,7 +319,7 @@ def test_extra_python_files_and_functions(testdir, recwarn): def check_method(self): assert 23 == 23 """) - # check that directory collects "check_" files + # check that directory collects "check_" files config = testdir.parseconfig() col = config.getnode(checkfile.dirpath()) colitems = col.collect() diff --git a/testing/test_funcargs.py b/testing/test_funcargs.py index b142d3db2..5b90ffe4f 100644 --- a/testing/test_funcargs.py +++ b/testing/test_funcargs.py @@ -3,7 +3,7 @@ from py._test import funcargs def test_getfuncargnames(): def f(): pass - assert not funcargs.getfuncargnames(f) + assert not funcargs.getfuncargnames(f) def g(arg): pass assert funcargs.getfuncargnames(g) == ['arg'] def h(arg1, arg2="hello"): pass @@ -19,7 +19,7 @@ def test_getfuncargnames(): def test_callspec_repr(): cs = funcargs.CallSpec({}, 'hello', 1) - repr(cs) + repr(cs) cs = funcargs.CallSpec({}, 'hello', funcargs._notexists) repr(cs) @@ -30,7 +30,7 @@ class TestFillFuncArgs: return 42 """) item = testdir.getitem("def test_func(some): pass") - exc = py.test.raises(funcargs.FuncargRequest.LookupError, + exc = py.test.raises(funcargs.FuncargRequest.LookupError, "funcargs.fillfuncargs(item)") s = str(exc.value) assert s.find("xyzsomething") != -1 @@ -48,7 +48,7 @@ class TestFillFuncArgs: item = testdir.getitem("def test_func(some, other): pass") class Provider: def pytest_funcarg__some(self, request): - return request.function.__name__ + return request.function.__name__ def pytest_funcarg__other(self, request): return 42 item.config.pluginmanager.register(Provider()) @@ -64,9 +64,9 @@ class TestFillFuncArgs: class TestClass: def test_method(self, something): - pass + pass def test_func(something): - pass + pass """) item1, item2 = testdir.genitems([modcol]) funcargs.fillfuncargs(item1) @@ -78,9 +78,9 @@ class TestFillFuncArgs: p = testdir.makepyfile(""" class TestClass: def pytest_funcarg__something(self, request): - return request.instance + return request.instance def test_method(self, something): - assert something is self + assert something is self """) result = testdir.runpytest(p) result.stdout.fnmatch_lines([ @@ -105,17 +105,17 @@ class TestRequest: def test_func(something): pass """) req = funcargs.FuncargRequest(item) - assert req.function == item.obj + assert req.function == item.obj assert hasattr(req.module, 'test_func') assert req.cls is None - assert req.function.__name__ == "test_func" - assert req.config == item.config + assert req.function.__name__ == "test_func" + assert req.config == item.config assert repr(req).find(req.function.__name__) != -1 def test_request_attributes_method(self, testdir): item, = testdir.getitems(""" class TestB: - def test_func(self, something): + def test_func(self, something): pass """) req = funcargs.FuncargRequest(item) @@ -144,29 +144,29 @@ class TestRequest: item = testdir.getitem(""" def pytest_funcarg__something(request): return request.getfuncargvalue("something") + 1 - def test_func(something): + def test_func(something): assert something == 2 """) req = funcargs.FuncargRequest(item) - val = req.getfuncargvalue("something") + val = req.getfuncargvalue("something") assert val == 2 def test_getfuncargvalue(self, testdir): item = testdir.getitem(""" l = [2] def pytest_funcarg__something(request): return 1 - def pytest_funcarg__other(request): + def pytest_funcarg__other(request): return l.pop() def test_func(something): pass """) req = funcargs.FuncargRequest(item) py.test.raises(req.LookupError, req.getfuncargvalue, "notexists") - val = req.getfuncargvalue("something") + val = req.getfuncargvalue("something") assert val == 1 - val = req.getfuncargvalue("something") + val = req.getfuncargvalue("something") assert val == 1 val2 = req.getfuncargvalue("other") - assert val2 == 2 + assert val2 == 2 val2 = req.getfuncargvalue("other") # see about caching assert val2 == 2 req._fillfuncargs() @@ -175,27 +175,27 @@ class TestRequest: def test_request_addfinalizer(self, testdir): item = testdir.getitem(""" teardownlist = [] - def pytest_funcarg__something(request): + def pytest_funcarg__something(request): request.addfinalizer(lambda: teardownlist.append(1)) def test_func(something): pass """) req = funcargs.FuncargRequest(item) - req.config._setupstate.prepare(item) # XXX + req.config._setupstate.prepare(item) # XXX req._fillfuncargs() - # successively check finalization calls - teardownlist = item.getparent(py.test.collect.Module).obj.teardownlist + # successively check finalization calls + teardownlist = item.getparent(py.test.collect.Module).obj.teardownlist ss = item.config._setupstate - assert not teardownlist - ss.teardown_exact(item) + assert not teardownlist + ss.teardown_exact(item) print(ss.stack) assert teardownlist == [1] def test_request_addfinalizer_partial_setup_failure(self, testdir): p = testdir.makepyfile(""" l = [] - def pytest_funcarg__something(request): + def pytest_funcarg__something(request): request.addfinalizer(lambda: l.append(None)) - def test_func(something, missingarg): + def test_func(something, missingarg): pass def test_second(): assert len(l) == 1 @@ -209,32 +209,32 @@ class TestRequest: modcol = testdir.getmodulecol("def test_somefunc(): pass") item, = testdir.genitems([modcol]) req = funcargs.FuncargRequest(item) - assert req.fspath == modcol.fspath + assert req.fspath == modcol.fspath def test_applymarker(testdir): item1,item2 = testdir.getitems(""" class TestClass: - def test_func1(self, something): + def test_func1(self, something): pass - def test_func2(self, something): + def test_func2(self, something): pass """) req1 = funcargs.FuncargRequest(item1) - assert 'xfail' not in item1.keywords + assert 'xfail' not in item1.keywords req1.applymarker(py.test.mark.xfail) - assert 'xfail' in item1.keywords - assert 'skipif' not in item1.keywords + assert 'xfail' in item1.keywords + assert 'skipif' not in item1.keywords req1.applymarker(py.test.mark.skipif) - assert 'skipif' in item1.keywords + assert 'skipif' in item1.keywords py.test.raises(ValueError, "req1.applymarker(42)") class TestRequestCachedSetup: def test_request_cachedsetup(self, testdir): item1,item2 = testdir.getitems(""" class TestClass: - def test_func1(self, something): + def test_func1(self, something): pass - def test_func2(self, something): + def test_func2(self, something): pass """) req1 = funcargs.FuncargRequest(item1) @@ -289,7 +289,7 @@ class TestRequestCachedSetup: def pytest_funcarg__arg2(request): return request.cached_setup(lambda: 17) def test_two_different_setups(arg1, arg2): - assert arg1 != arg2 + assert arg1 != arg2 """) result = testdir.runpytest("-v") result.stdout.fnmatch_lines([ @@ -316,10 +316,10 @@ class TestRequestCachedSetup: l = [] def pytest_funcarg__something(request): val = request.cached_setup(setup, teardown) - return val + return val def setup(mycache=[1]): l.append(mycache.pop()) - return l + return l def teardown(something): l.remove(something[0]) l.append(2) @@ -329,7 +329,7 @@ class TestRequestCachedSetup: assert something == [1] """) testdir.makepyfile(test_1=""" - import test_0 # should have run already + import test_0 # should have run already def test_check_test0_has_teardown_correct(): assert test_0.l == [2] """) @@ -349,7 +349,7 @@ class TestMetafunc: metafunc = funcargs.Metafunc(func) assert len(metafunc.funcargnames) == 1 assert 'arg1' in metafunc.funcargnames - assert metafunc.function is func + assert metafunc.function is func assert metafunc.cls is None def test_addcall_no_args(self): @@ -377,19 +377,19 @@ class TestMetafunc: def test_addcall_param(self): def func(arg1): pass metafunc = funcargs.Metafunc(func) - class obj: pass - metafunc.addcall(param=obj) - metafunc.addcall(param=obj) - metafunc.addcall(param=1) + class obj: pass + metafunc.addcall(param=obj) + metafunc.addcall(param=obj) + metafunc.addcall(param=1) assert len(metafunc._calls) == 3 - assert metafunc._calls[0].param == obj - assert metafunc._calls[1].param == obj + assert metafunc._calls[0].param == obj + assert metafunc._calls[1].param == obj assert metafunc._calls[2].param == 1 def test_addcall_funcargs(self): def func(arg1): pass metafunc = funcargs.Metafunc(func) - class obj: pass + class obj: pass metafunc.addcall(funcargs={"x": 2}) metafunc.addcall(funcargs={"x": 3}) assert len(metafunc._calls) == 2 @@ -403,11 +403,11 @@ class TestGenfuncFunctional: # assumes that generate/provide runs in the same process import py def pytest_generate_tests(metafunc): - metafunc.addcall(param=metafunc) + metafunc.addcall(param=metafunc) def pytest_funcarg__metafunc(request): assert request._pyfuncitem._genid == "0" - return request.param + return request.param def test_function(metafunc, pytestconfig): assert metafunc.config == pytestconfig @@ -435,7 +435,7 @@ class TestGenfuncFunctional: def test_addcall_with_two_funcargs_generators(self, testdir): testdir.makeconftest(""" def pytest_generate_tests(metafunc): - assert "arg1" in metafunc.funcargnames + assert "arg1" in metafunc.funcargnames metafunc.addcall(funcargs=dict(arg1=1, arg2=2)) """) p = testdir.makepyfile(""" @@ -444,12 +444,12 @@ class TestGenfuncFunctional: class TestClass: def test_myfunc(self, arg1, arg2): - assert arg1 == arg2 + assert arg1 == arg2 """) result = testdir.runpytest("-v", p) result.stdout.fnmatch_lines([ - "*test_myfunc*0*PASS*", - "*test_myfunc*1*FAIL*", + "*test_myfunc*0*PASS*", + "*test_myfunc*1*FAIL*", "*1 failed, 1 passed*" ]) @@ -457,7 +457,7 @@ class TestGenfuncFunctional: p = testdir.makepyfile(""" def pytest_generate_tests(metafunc): metafunc.addcall(param=10) - metafunc.addcall(param=20) + metafunc.addcall(param=20) def pytest_funcarg__arg1(request): return request.param @@ -469,8 +469,8 @@ class TestGenfuncFunctional: """) result = testdir.runpytest("-v", p) result.stdout.fnmatch_lines([ - "*test_func1*0*PASS*", - "*test_func1*1*FAIL*", + "*test_func1*0*PASS*", + "*test_func1*1*FAIL*", "*test_func2*PASS*", "*1 failed, 3 passed*" ]) @@ -478,7 +478,7 @@ class TestGenfuncFunctional: def test_generate_plugin_and_module(self, testdir): testdir.makeconftest(""" def pytest_generate_tests(metafunc): - assert "arg1" in metafunc.funcargnames + assert "arg1" in metafunc.funcargnames metafunc.addcall(id="world", param=(2,100)) """) p = testdir.makepyfile(""" @@ -492,12 +492,12 @@ class TestGenfuncFunctional: class TestClass: def test_myfunc(self, arg1, arg2): - assert arg1 == arg2 + assert arg1 == arg2 """) result = testdir.runpytest("-v", p) result.stdout.fnmatch_lines([ - "*test_myfunc*hello*PASS*", - "*test_myfunc*world*FAIL*", + "*test_myfunc*hello*PASS*", + "*test_myfunc*world*FAIL*", "*1 failed, 1 passed*" ]) @@ -512,7 +512,7 @@ class TestGenfuncFunctional: """) result = testdir.runpytest("-v", p) result.stdout.fnmatch_lines([ - "*test_myfunc*hello*PASS*", + "*test_myfunc*hello*PASS*", "*1 passed*" ]) @@ -529,8 +529,8 @@ class TestGenfuncFunctional: """) result = testdir.runpytest("-v", p) result.stdout.fnmatch_lines([ - "*test_func*0*PASS*", - "*test_func*1*PASS*", + "*test_func*0*PASS*", + "*test_func*1*PASS*", "*2 pass*", ]) @@ -576,7 +576,7 @@ def test_funcarg_non_pycollectobj(testdir): # rough jstests usage clscol.obj = lambda arg1: None clscol.funcargs = {} funcargs.fillfuncargs(clscol) - assert clscol.funcargs['arg1'] == 42 + assert clscol.funcargs['arg1'] == 42 def test_funcarg_lookup_error(testdir): @@ -592,4 +592,4 @@ def test_funcarg_lookup_error(testdir): "*available funcargs*", "*1 error*", ]) - assert "INTERNAL" not in result.stdout.str() + assert "INTERNAL" not in result.stdout.str() diff --git a/testing/test_genitems.py b/testing/test_genitems.py index 876f4ee5b..0ac94e444 100644 --- a/testing/test_genitems.py +++ b/testing/test_genitems.py @@ -1,6 +1,6 @@ import py -class Test_genitems: +class Test_genitems: def test_check_collect_hashes(self, testdir): p = testdir.makepyfile(""" def test_1(): @@ -17,13 +17,13 @@ class Test_genitems: if numj != numi: assert hash(i) != hash(j) assert i != j - + def test_root_conftest_syntax_error(self, testdir): # do we want to unify behaviour with - # test_subdir_conftest_error? + # test_subdir_conftest_error? p = testdir.makepyfile(conftest="raise SyntaxError\n") py.test.raises(SyntaxError, testdir.inline_genitems, p.dirpath()) - + def test_example_items1(self, testdir): p = testdir.makepyfile(''' def testone(): @@ -56,15 +56,15 @@ class TestKeywordSelection: def test_select_simple(self, testdir): file_test = testdir.makepyfile(""" def test_one(): assert 0 - class TestClass(object): - def test_method_one(self): - assert 42 == 43 + class TestClass(object): + def test_method_one(self): + assert 42 == 43 """) def check(keyword, name): reprec = testdir.inline_run("-s", "-k", keyword, file_test) passed, skipped, failed = reprec.listoutcomes() assert len(failed) == 1 - assert failed[0].item.name == name + assert failed[0].item.name == name assert len(reprec.getcalls('pytest_deselected')) == 1 for keyword in ['test_one', 'est_on']: @@ -75,19 +75,19 @@ class TestKeywordSelection: def test_select_extra_keywords(self, testdir): p = testdir.makepyfile(test_select=""" def test_1(): - pass - class TestClass: - def test_2(self): + pass + class TestClass: + def test_2(self): pass """) testdir.makepyfile(conftest=""" import py - class Class(py.test.collect.Class): + class Class(py.test.collect.Class): def _keywords(self): return ['xxx', self.name] """) - for keyword in ('xxx', 'xxx test_2', 'TestClass', 'xxx -test_1', - 'TestClass test_2', 'xxx TestClass test_2',): + for keyword in ('xxx', 'xxx test_2', 'TestClass', 'xxx -test_1', + 'TestClass test_2', 'xxx TestClass test_2',): reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword) py.builtin.print_("keyword", repr(keyword)) passed, skipped, failed = reprec.listoutcomes() @@ -106,22 +106,22 @@ class TestKeywordSelection: reprec = testdir.inline_run("-k", "test_two:", threepass) passed, skipped, failed = reprec.listoutcomes() assert len(passed) == 2 - assert not failed + assert not failed dlist = reprec.getcalls("pytest_deselected") assert len(dlist) == 1 item = dlist[0].items[0] - assert item.name == "test_one" + assert item.name == "test_one" def test_keyword_extra(self, testdir): p = testdir.makepyfile(""" - def test_one(): - assert 0 + def test_one(): + assert 0 test_one.mykeyword = True """) reprec = testdir.inline_run("-k", "-mykeyword", p) passed, skipped, failed = reprec.countoutcomes() - assert passed + skipped + failed == 0 + assert passed + skipped + failed == 0 reprec = testdir.inline_run("-k", "mykeyword", p) passed, skipped, failed = reprec.countoutcomes() assert failed == 1 diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 425333768..ee919d95c 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -37,8 +37,8 @@ class TestBootstrapping: l1 = len(pluginmanager.getplugins()) pluginmanager.consider_env() l2 = len(pluginmanager.getplugins()) - assert l2 == l1 + 1 - assert pluginmanager.getplugin('pytest_xy123') + assert l2 == l1 + 1 + assert pluginmanager.getplugin('pytest_xy123') pluginmanager.consider_env() l3 = len(pluginmanager.getplugins()) assert l2 == l3 @@ -54,7 +54,7 @@ class TestBootstrapping: x = 42 return PseudoPlugin() return iter([EntryPoint()]) - + monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter) pluginmanager = PluginManager() pluginmanager.consider_setuptools_entrypoints() @@ -64,7 +64,7 @@ class TestBootstrapping: assert plugin2 == plugin def test_consider_setuptools_not_installed(self, monkeypatch): - monkeypatch.setitem(py.std.sys.modules, 'pkg_resources', + monkeypatch.setitem(py.std.sys.modules, 'pkg_resources', py.std.types.ModuleType("pkg_resources")) pluginmanager = PluginManager() pluginmanager.consider_setuptools_entrypoints() @@ -116,7 +116,7 @@ class TestBootstrapping: mod = py.std.types.ModuleType("x") mod.pytest_plugins = "pytest_a" aplugin = testdir.makepyfile(pytest_a="#") - pluginmanager = PluginManager() + pluginmanager = PluginManager() reprec = testdir.getreportrecorder(pluginmanager) #syspath.prepend(aplugin.dirpath()) py.std.sys.path.insert(0, str(aplugin.dirpath())) @@ -124,7 +124,7 @@ class TestBootstrapping: call = reprec.getcall(pluginmanager.hook.pytest_plugin_registered.name) assert call.plugin.__name__ == "pytest_a" - # check that it is not registered twice + # check that it is not registered twice pluginmanager.consider_module(mod) l = reprec.getcalls("pytest_plugin_registered") assert len(l) == 1 @@ -145,14 +145,14 @@ class TestBootstrapping: def test_registry(self): pp = PluginManager() - class A: pass + class A: pass a1, a2 = A(), A() pp.register(a1) assert pp.isregistered(a1) pp.register(a2, "hello") assert pp.isregistered(a2) l = pp.getplugins() - assert a1 in l + assert a1 in l assert a2 in l assert pp.getplugin('hello') == a2 pp.unregister(a1) @@ -166,10 +166,10 @@ class TestBootstrapping: pp.register(mod) assert pp.isregistered(mod) l = pp.getplugins() - assert mod in l + assert mod in l py.test.raises(AssertionError, "pp.register(mod)") mod2 = py.std.types.ModuleType("pytest_hello") - #pp.register(mod2) # double registry + #pp.register(mod2) # double registry py.test.raises(AssertionError, "pp.register(mod)") #assert not pp.isregistered(mod2) assert pp.getplugins() == l @@ -204,7 +204,7 @@ class TestBootstrapping: class TestPytestPluginInteractions: def test_addhooks_conftestplugin(self, testdir): - from py._test.config import Config + from py._test.config import Config newhooks = testdir.makepyfile(newhooks=""" def pytest_myhook(xyz): "new hook" @@ -217,7 +217,7 @@ class TestPytestPluginInteractions: def pytest_myhook(xyz): return xyz + 1 """) - config = Config() + config = Config() config._conftest.importconftest(conf) print(config.pluginmanager.getplugins()) res = config.hook.pytest_myhook(xyz=10) @@ -244,7 +244,7 @@ class TestPytestPluginInteractions: def test_addhooks_nohooks(self, testdir): conf = testdir.makeconftest(""" - import sys + import sys def pytest_addhooks(pluginmanager): pluginmanager.addhooks(sys) """) @@ -255,12 +255,12 @@ class TestPytestPluginInteractions: ]) def test_do_option_conftestplugin(self, testdir): - from py._test.config import Config + from py._test.config import Config p = testdir.makepyfile(""" def pytest_addoption(parser): parser.addoption('--test123', action="store_true") """) - config = Config() + config = Config() config._conftest.importconftest(p) print(config.pluginmanager.getplugins()) config.parse([]) @@ -272,26 +272,26 @@ class TestPytestPluginInteractions: return {'hello': 'world'} """) p = testdir.makepyfile(""" - from py.test import hello + from py.test import hello import py def test_hello(): - assert hello == "world" + assert hello == "world" assert 'hello' in py.test.__all__ """) - result = testdir.runpytest(p) + result = testdir.runpytest(p) result.stdout.fnmatch_lines([ "*1 passed*" ]) def test_do_option_postinitialize(self, testdir): - from py._test.config import Config - config = Config() + from py._test.config import Config + config = Config() config.parse([]) config.pluginmanager.do_configure(config=config) assert not hasattr(config.option, 'test123') p = testdir.makepyfile(""" def pytest_addoption(parser): - parser.addoption('--test123', action="store_true", + parser.addoption('--test123', action="store_true", default=True) """) config._conftest.importconftest(p) @@ -303,7 +303,7 @@ class TestPytestPluginInteractions: class A: def pytest_configure(self, config): l.append(self) - + config.pluginmanager.register(A()) assert len(l) == 0 config.pluginmanager.do_configure(config=config) @@ -311,7 +311,7 @@ class TestPytestPluginInteractions: config.pluginmanager.register(A()) # this should lead to a configured() plugin assert len(l) == 2 assert l[0] != l[1] - + config.pluginmanager.do_unconfigure(config=config) config.pluginmanager.register(A()) assert len(l) == 2 @@ -329,7 +329,7 @@ class TestPytestPluginInteractions: def test_namespace_has_default_and_env_plugins(testdir): p = testdir.makepyfile(""" import py - py.test.mark + py.test.mark """) result = testdir.runpython(p) assert result.ret == 0 @@ -342,7 +342,7 @@ def test_varnames(): pass assert varnames(f) == ("x",) assert varnames(A().f) == ('y',) - + class TestMultiCall: def test_uses_copy_of_methods(self): l = [lambda: 42] @@ -363,19 +363,19 @@ class TestMultiCall: def m(self, __multicall__, x): assert __multicall__.results == [] assert __multicall__.methods - return 23 - - p1 = P1() - p2 = P2() + return 23 + + p1 = P1() + p2 = P2() multicall = MultiCall([p1.m, p2.m], {'x': 23}) assert "23" in repr(multicall) reslist = multicall.execute() assert len(reslist) == 2 - # ensure reversed order + # ensure reversed order assert reslist == [23, 17] def test_keyword_args(self): - def f(x): + def f(x): return x + 1 class A: def f(self, x, y): @@ -477,7 +477,7 @@ class TestHookRelay: def test_firstresult_definition(self): registry = Registry() class Api: - def hello(self, arg): + def hello(self, arg): "api hook 1" hello.firstresult = True diff --git a/testing/test_pycollect.py b/testing/test_pycollect.py index 606051520..feb3f418f 100644 --- a/testing/test_pycollect.py +++ b/testing/test_pycollect.py @@ -6,7 +6,7 @@ class TestModule: fn = tmpdir.join('nada','no') col = py.test.collect.Module(fn, config=testdir.Config()) col.config = testdir.parseconfig(tmpdir) - py.test.raises(py.error.ENOENT, col.collect) + py.test.raises(py.error.ENOENT, col.collect) def test_failing_import(self, testdir): modcol = testdir.getmodulecol("import alksdjalskdjalkjals") @@ -32,7 +32,7 @@ class TestModule: ]) def test_syntax_error_in_module(self, testdir): - modcol = testdir.getmodulecol("this is a syntax error") + modcol = testdir.getmodulecol("this is a syntax error") py.test.raises(modcol.CollectError, modcol.collect) py.test.raises(modcol.CollectError, modcol.collect) py.test.raises(modcol.CollectError, modcol.run) @@ -46,12 +46,12 @@ class TestClass: modcol = testdir.getmodulecol(""" class TestClass1: def __init__(self): - pass + pass class TestClass2(object): def __init__(self): - pass + pass """) - l = modcol.collect() + l = modcol.collect() assert len(l) == 0 if py.std.sys.version_info > (3, 0): @@ -60,12 +60,12 @@ else: _func_name_attr = "func_name" class TestGenerator: - def test_generative_functions(self, testdir): + def test_generative_functions(self, testdir): modcol = testdir.getmodulecol(""" - def func1(arg, arg2): - assert arg == arg2 + def func1(arg, arg2): + assert arg == arg2 - def test_gen(): + def test_gen(): yield func1, 17, 3*5 yield func1, 42, 6*7 """) @@ -80,12 +80,12 @@ class TestGenerator: assert gencolitems[0].name == '[0]' assert getattr(gencolitems[0].obj, _func_name_attr) == 'func1' - def test_generative_methods(self, testdir): + def test_generative_methods(self, testdir): modcol = testdir.getmodulecol(""" - def func1(arg, arg2): - assert arg == arg2 - class TestGenMethods: - def test_gen(self): + def func1(arg, arg2): + assert arg == arg2 + class TestGenMethods: + def test_gen(self): yield func1, 17, 3*5 yield func1, 42, 6*7 """) @@ -100,10 +100,10 @@ class TestGenerator: def test_generative_functions_with_explicit_names(self, testdir): modcol = testdir.getmodulecol(""" - def func1(arg, arg2): - assert arg == arg2 + def func1(arg, arg2): + assert arg == arg2 - def test_gen(): + def test_gen(): yield "seventeen", func1, 17, 3*5 yield "fortytwo", func1, 42, 6*7 """) @@ -118,13 +118,13 @@ class TestGenerator: assert gencolitems[0].name == "['seventeen']" assert getattr(gencolitems[0].obj, _func_name_attr) == 'func1' assert gencolitems[1].name == "['fortytwo']" - assert getattr(gencolitems[1].obj, _func_name_attr) == 'func1' + assert getattr(gencolitems[1].obj, _func_name_attr) == 'func1' def test_generative_functions_unique_explicit_names(self, testdir): - # generative + # generative modcol = testdir.getmodulecol(""" - def func(): pass - def test_gen(): + def func(): pass + def test_gen(): yield "name", func yield "name", func """) @@ -134,12 +134,12 @@ class TestGenerator: assert isinstance(gencol, py.test.collect.Generator) py.test.raises(ValueError, "gencol.collect()") - def test_generative_methods_with_explicit_names(self, testdir): + def test_generative_methods_with_explicit_names(self, testdir): modcol = testdir.getmodulecol(""" - def func1(arg, arg2): - assert arg == arg2 - class TestGenMethods: - def test_gen(self): + def func1(arg, arg2): + assert arg == arg2 + class TestGenMethods: + def test_gen(self): yield "m1", func1, 17, 3*5 yield "m2", func1, 42, 6*7 """) @@ -152,7 +152,7 @@ class TestGenerator: assert gencolitems[0].name == "['m1']" assert getattr(gencolitems[0].obj, _func_name_attr) == 'func1' assert gencolitems[1].name == "['m2']" - assert getattr(gencolitems[1].obj, _func_name_attr) == 'func1' + assert getattr(gencolitems[1].obj, _func_name_attr) == 'func1' def test_order_of_execution_generator_same_codeline(self, testdir, tmpdir): o = testdir.makepyfile(""" @@ -163,20 +163,20 @@ class TestGenerator: def list_append(item): test_list.append(item) - + def assert_order_of_execution(): py.builtin.print_('expected order', expected_list) py.builtin.print_('but got ', test_list) assert test_list == expected_list - + for i in expected_list: yield list_append, i yield assert_order_of_execution """) reprec = testdir.inline_run(o) - passed, skipped, failed = reprec.countoutcomes() + passed, skipped, failed = reprec.countoutcomes() assert passed == 7 - assert not skipped and not failed + assert not skipped and not failed def test_order_of_execution_generator_different_codeline(self, testdir): o = testdir.makepyfile(""" @@ -198,16 +198,16 @@ class TestGenerator: py.builtin.print_('expected order', expected_list) py.builtin.print_('but got ', test_list) assert test_list == expected_list - + yield list_append_0 yield list_append_1 yield list_append_2 - yield assert_order_of_execution + yield assert_order_of_execution """) - reprec = testdir.inline_run(o) - passed, skipped, failed = reprec.countoutcomes() + reprec = testdir.inline_run(o) + passed, skipped, failed = reprec.countoutcomes() assert passed == 4 - assert not skipped and not failed + assert not skipped and not failed class TestFunction: def test_getmodulecollector(self, testdir): @@ -215,16 +215,16 @@ class TestFunction: modcol = item.getparent(py.test.collect.Module) assert isinstance(modcol, py.test.collect.Module) assert hasattr(modcol.obj, 'test_func') - + def test_function_equality(self, testdir, tmpdir): config = testdir.reparseconfig() f1 = py.test.collect.Function(name="name", config=config, args=(1,), callobj=isinstance) - f2 = py.test.collect.Function(name="name",config=config, + f2 = py.test.collect.Function(name="name",config=config, args=(1,), callobj=py.builtin.callable) assert not f1 == f2 assert f1 != f2 - f3 = py.test.collect.Function(name="name", config=config, + f3 = py.test.collect.Function(name="name", config=config, args=(1,2), callobj=py.builtin.callable) assert not f3 == f2 assert f3 != f2 @@ -232,7 +232,7 @@ class TestFunction: assert not f3 == f1 assert f3 != f1 - f1_b = py.test.collect.Function(name="name", config=config, + f1_b = py.test.collect.Function(name="name", config=config, args=(1,), callobj=isinstance) assert f1 == f1_b assert not f1 != f1_b @@ -247,9 +247,9 @@ class TestFunction: param = 1 funcargs = {} id = "world" - f5 = py.test.collect.Function(name="name", config=config, + f5 = py.test.collect.Function(name="name", config=config, callspec=callspec1, callobj=isinstance) - f5b = py.test.collect.Function(name="name", config=config, + f5b = py.test.collect.Function(name="name", config=config, callspec=callspec2, callobj=isinstance) assert f5 != f5b assert not (f5 == f5b) @@ -282,11 +282,11 @@ class TestSorting: assert fn1 != modcol if py.std.sys.version_info < (3, 0): assert cmp(fn1, fn2) == 0 - assert hash(fn1) == hash(fn2) + assert hash(fn1) == hash(fn2) fn3 = modcol.collect_by_name("test_fail") assert isinstance(fn3, py.test.collect.Function) - assert not (fn1 == fn3) + assert not (fn1 == fn3) assert fn1 != fn3 for fn in fn1,fn2,fn3: @@ -349,22 +349,22 @@ class TestConftestCustomization: result.stdout.fnmatch_lines([ "*MyFunction*some*", ]) - + def test_makeitem_non_underscore(self, testdir, monkeypatch): modcol = testdir.getmodulecol("def _hello(): pass") l = [] - monkeypatch.setattr(py.test.collect.Module, 'makeitem', + monkeypatch.setattr(py.test.collect.Module, 'makeitem', lambda self, name, obj: l.append(name)) l = modcol.collect() assert '_hello' not in l class TestReportinfo: - + def test_func_reportinfo(self, testdir): item = testdir.getitem("def test_func(): pass") fspath, lineno, modpath = item.reportinfo() - assert fspath == item.fspath + assert fspath == item.fspath assert lineno == 0 assert modpath == "test_func" @@ -376,15 +376,15 @@ class TestReportinfo: """) classcol = modcol.collect_by_name("TestClass") fspath, lineno, msg = classcol.reportinfo() - assert fspath == modcol.fspath + assert fspath == modcol.fspath assert lineno == 1 assert msg == "TestClass" def test_generator_reportinfo(self, testdir): modcol = testdir.getmodulecol(""" # lineno 0 - def test_gen(): - def check(x): + def test_gen(): + def check(x): assert x yield check, 3 """) @@ -495,7 +495,7 @@ class TestTracebackCutting: x = 1 x = 2 x = 17 - asd + asd """) result = testdir.runpytest() assert result.ret != 0 diff --git a/testing/test_session.py b/testing/test_session.py index 7a3b6a959..a09d3bc30 100644 --- a/testing/test_session.py +++ b/testing/test_session.py @@ -4,11 +4,11 @@ class SessionTests: def test_initsession(self, testdir, tmpdir): config = testdir.reparseconfig() session = config.initsession() - assert session.config is config - + assert session.config is config + def test_basic_testitem_events(self, testdir): tfile = testdir.makepyfile(""" - def test_one(): + def test_one(): pass def test_one_one(): assert 0 @@ -21,7 +21,7 @@ class SessionTests: passed, skipped, failed = reprec.listoutcomes() assert len(skipped) == 0 assert len(passed) == 1 - assert len(failed) == 3 + assert len(failed) == 3 assert failed[0].item.name == "test_one_one" assert failed[1].item.name == "test_other" assert failed[2].item.name == "test_two" @@ -32,22 +32,22 @@ class SessionTests: col = colstarted[0].collector assert isinstance(col, py.test.collect.Module) - def test_nested_import_error(self, testdir): + def test_nested_import_error(self, testdir): tfile = testdir.makepyfile(""" import import_fails def test_this(): assert import_fails.a == 1 """, import_fails=""" - import does_not_work + import does_not_work a = 1 """) reprec = testdir.inline_run(tfile) l = reprec.getfailedcollections() - assert len(l) == 1 + assert len(l) == 1 out = l[0].longrepr.reprcrash.message - assert out.find('does_not_work') != -1 + assert out.find('does_not_work') != -1 - def test_raises_output(self, testdir): + def test_raises_output(self, testdir): reprec = testdir.inline_runsource(""" import py def test_raises_doesnt(): @@ -56,28 +56,28 @@ class SessionTests: passed, skipped, failed = reprec.listoutcomes() assert len(failed) == 1 out = failed[0].longrepr.reprcrash.message - if not out.find("DID NOT RAISE") != -1: + if not out.find("DID NOT RAISE") != -1: print(out) - py.test.fail("incorrect raises() output") + py.test.fail("incorrect raises() output") - def test_generator_yields_None(self, testdir): + def test_generator_yields_None(self, testdir): reprec = testdir.inline_runsource(""" def test_1(): - yield None + yield None """) failures = reprec.getfailedcollections() out = failures[0].longrepr.reprcrash.message - i = out.find('TypeError') - assert i != -1 + i = out.find('TypeError') + assert i != -1 - def test_syntax_error_module(self, testdir): + def test_syntax_error_module(self, testdir): reprec = testdir.inline_runsource("this is really not python") l = reprec.getfailedcollections() assert len(l) == 1 out = str(l[0].longrepr) assert out.find(str('not python')) != -1 - def test_exit_first_problem(self, testdir): + def test_exit_first_problem(self, testdir): reprec = testdir.inline_runsource(""" def test_one(): assert 0 def test_two(): assert 0 @@ -86,7 +86,7 @@ class SessionTests: assert failed == 1 assert passed == skipped == 0 - def test_maxfail(self, testdir): + def test_maxfail(self, testdir): reprec = testdir.inline_runsource(""" def test_one(): assert 0 def test_two(): assert 0 @@ -103,12 +103,12 @@ class SessionTests: foo=0 def __repr__(self): raise Exception("Ha Ha fooled you, I'm a broken repr().") - + class TestBrokenClass: def test_explicit_bad_repr(self): t = BrokenRepr1() py.test.raises(Exception, 'repr(t)') - + def test_implicit_bad_repr1(self): t = BrokenRepr1() assert t.foo == 1 @@ -132,11 +132,11 @@ class SessionTests: reprec = testdir.inline_run(testdir.tmpdir) reports = reprec.getreports("pytest_collectreport") assert len(reports) == 1 - assert reports[0].skipped + assert reports[0].skipped class TestNewSession(SessionTests): - def test_order_of_execution(self, testdir): + def test_order_of_execution(self, testdir): reprec = testdir.inline_runsource(""" l = [] def test_1(): @@ -159,7 +159,7 @@ class TestNewSession(SessionTests): passed, skipped, failed = reprec.countoutcomes() assert failed == skipped == 0 assert passed == 7 - # also test listnames() here ... + # also test listnames() here ... def test_collect_only_with_various_situations(self, testdir): p = testdir.makepyfile( @@ -173,23 +173,23 @@ class TestNewSession(SessionTests): class TestY(TestX): pass - """, + """, test_two=""" import py py.test.skip('xxx') - """, + """, test_three="xxxdsadsadsadsa", __init__="" ) reprec = testdir.inline_run('--collectonly', p.dirpath()) - + itemstarted = reprec.getcalls("pytest_itemstart") assert len(itemstarted) == 3 - assert not reprec.getreports("pytest_runtest_logreport") + assert not reprec.getreports("pytest_runtest_logreport") started = reprec.getcalls("pytest_collectstart") finished = reprec.getreports("pytest_collectreport") - assert len(started) == len(finished) - assert len(started) == 8 + assert len(started) == len(finished) + assert len(started) == 8 colfail = [x for x in finished if x.failed] colskipped = [x for x in finished if x.skipped] assert len(colfail) == 1