From commits-noreply at bitbucket.org Thu Jan 2 21:15:26 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 02 Jan 2014 20:15:26 -0000 Subject: [Pytest-commit] commit/pytest: jurko: correct documentation typo Message-ID: <20140102201526.8872.5022@app11.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/e2d2870e7437/ Changeset: e2d2870e7437 User: jurko Date: 2013-12-28 17:05:17 Summary: correct documentation typo Affected #: 1 file diff -r 17a246750c75f5eda01d065b9c72ab9fb0f1b544 -r e2d2870e7437c8828e8779b63a9b499bc937b1fc doc/en/parametrize.txt --- a/doc/en/parametrize.txt +++ b/doc/en/parametrize.txt @@ -114,8 +114,8 @@ In versions prior to 2.4 one needed to specify the argument names as a tuple. This remains valid but the simpler ``"name1,name2,..."`` - comma-separated-string syntax is now advertised fist because - it's easier to write, produces less line noise. + comma-separated-string syntax is now advertised first because + it's easier to write and produces less line noise. .. _`pytest_generate_tests`: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 2 21:16:43 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 02 Jan 2014 20:16:43 -0000 Subject: [Pytest-commit] commit/tox: techtonik: allow to run tox as 'python -m tox', which is handy on Windoze Message-ID: <20140102201643.22206.80696@app10.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/4542c26e2a8a/ Changeset: 4542c26e2a8a User: techtonik Date: 2013-12-30 17:52:09 Summary: allow to run tox as 'python -m tox', which is handy on Windoze Affected #: 1 file diff -r cec6988e5dbd7b63bd61fd50394a7f8c007450f2 -r 4542c26e2a8ad4f1708abe8a2a2024a4825b6e3f tox/__main__.py --- /dev/null +++ b/tox/__main__.py @@ -0,0 +1,3 @@ +from tox._cmdline import main + +main() Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Wed Jan 8 14:37:25 2014 From: issues-reply at bitbucket.org (faassen) Date: Wed, 08 Jan 2014 13:37:25 -0000 Subject: [Pytest-commit] Issue #142: tox on buildout (hpk42/tox) Message-ID: <20140108133725.4509.89191@app18.ash-private.bitbucket.org> New issue 142: tox on buildout https://bitbucket.org/hpk42/tox/issue/142/tox-on-buildout faassen: I've tried using tox from within a buildout. I can easily get tox installed, and then have a 'bin/tox' available in my buildout. When I run it however I get errors like this: ``` Already using interpreter /usr/bin/python2.7 New python executable in py27/bin/python2.7 Also creating executable in py27/bin/python Installing setuptools, pip... Complete output from command /home/faassen/projec...x/py27/bin/python2.7 -c "import sys, pip; pip...ll\"] + sys.argv[1:])" setuptools pip: Traceback (most recent call last): File "", line 1, in File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/pip-1.5-py2.py3-none-any.whl/pip/__init__.py", line 9, in File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/pip-1.5-py2.py3-none-any.whl/pip/log.py", line 8, in File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/setuptools-2.0.2-py2.py3-none-any.whl/pkg_resources.py", line 2696, in File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/setuptools-2.0.2-py2.py3-none-any.whl/pkg_resources.py", line 429, in __init__ File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/setuptools-2.0.2-py2.py3-none-any.whl/pkg_resources.py", line 443, in add_entry File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/setuptools-2.0.2-py2.py3-none-any.whl/pkg_resources.py", line 1722, in find_in_zip File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/setuptools-2.0.2-py2.py3-none-any.whl/pkg_resources.py", line 1298, in has_metadata File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/setuptools-2.0.2-py2.py3-none-any.whl/pkg_resources.py", line 1614, in _has File "/home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/setuptools-2.0.2-py2.py3-none-any.whl/pkg_resources.py", line 1488, in _zipinfo_name AssertionError: /home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/EGG-INFO/PKG-INFO is not a subpath of /home/faassen/.buildout/eggs/virtualenv-1.11-py2.7.egg/virtualenv_support/setuptools-2.0.2-py2.py3-none-any.whl/ ``` When I run with a tox I installed in a virtualenv, it does work. *after* that if I run bin/tox again, it works, even if I remove .tox before. Somehow the virtualenv tox invocation magically fixes things. Just the installation of tox in a virtualenv by itself won't do the trick though - only invocation of that tox does the magic fix. How I install the buildout: $ virtualenv ve $ ve/bin/python bootstrap.py $ bin/buildout then to run the failing tox: $ bin/tox You can find the minimal buildout to test this here: https://github.com/faassen/buildouttox From issues-reply at bitbucket.org Wed Jan 8 16:58:38 2014 From: issues-reply at bitbucket.org (faassen) Date: Wed, 08 Jan 2014 15:58:38 -0000 Subject: [Pytest-commit] Issue #143: projects with setup.py as tox test fixtures (hpk42/tox) Message-ID: <20140108155838.24461.79112@app11.ash-private.bitbucket.org> New issue 143: projects with setup.py as tox test fixtures https://bitbucket.org/hpk42/tox/issue/143/projects-with-setuppy-as-tox-test-fixtures faassen: I have code that needs Python projects with a setup.py as test fixtures. This is because I'm testing code that inspects their requirements using pkg_resources. The actual code in the test fixtures is not so important, though features in my test too, as that code if important if certain conditions hold true about the requirements. It makes no sense to publish these test fixture projects on pypi or any other package index: they're just test fixtures, after all. With buildout I can simply point to the fixture's project directory (with the setup.py in it) and it will make sure that project is installed. With tox I don't see a way how to do this. This blocks me from using tox in my project (Morepath). I wanted to use tox as a tool to help me make sure it runs with PyPy and Python 3; without tox this is much more cumbersome. I'll note that having the ability to install directories as projects would also help with a previous use case I had: I wanted to run tox-based tests without having to publish the code of a dependent library on a package index. Here's a buildout-inspired possible way to configure this. Add something like this to tox.ini: ``` develop = fixtures/test_package my_dependency_under_development ``` tox can then look in those listed directories, which are presumed to have a setup.py, and install them into the test environment. for those packages tox won't go off and try to download them from an index. If the situation occurs that the requirements don't match, i.e. the develop package has dependency 0.1 and another setup.py tries to pull in dependency 0.2, perhaps we should fail loudly instead of silently downloading dependency 0.2 and letting the user believe their local directory is under test. [develop From commits-noreply at bitbucket.org Fri Jan 10 10:43:40 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 10 Jan 2014 09:43:40 -0000 Subject: [Pytest-commit] commit/pytest: Daniel Hahler: doc: fix desc for `parametrize` Message-ID: <20140110094340.19868.27037@app12.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/d76058834af2/ Changeset: d76058834af2 User: Daniel Hahler Date: 2014-01-09 22:27:23 Summary: doc: fix desc for `parametrize` - the parameter is called `expected`, not `output` - s/that that/that/ Affected #: 1 file diff -r e2d2870e7437c8828e8779b63a9b499bc937b1fc -r d76058834af217b7d319bac2549d6f8841564ef9 doc/en/parametrize.txt --- a/doc/en/parametrize.txt +++ b/doc/en/parametrize.txt @@ -47,8 +47,8 @@ def test_eval(input, expected): assert eval(input) == expected -Here, the ``@parametrize`` decorator defines three different ``(input,output)`` -tuples so that that the ``test_eval`` function will run three times using +Here, the ``@parametrize`` decorator defines three different ``(input,expected)`` +tuples so that the ``test_eval`` function will run three times using them in turn:: $ py.test Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Jan 10 10:44:15 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 10 Jan 2014 09:44:15 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140110094415.3478.38301@app07.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/a1982261e07c/ Changeset: a1982261e07c Branch: /minor-doc-fix-in-skippingtxt-also-submi-1387492852421 User: lakka Date: 2013-12-19 23:41:07 Summary: Minor doc fix in skipping.txt. Also submitted at Github before I realised that this was the master repo. Will close over there. Affected #: 1 file diff -r 91925448ac067edf770b504d199a8998872a9f10 -r a1982261e07cac11858b2683fff4e097c981c0b1 doc/en/skipping.txt --- a/doc/en/skipping.txt +++ b/doc/en/skipping.txt @@ -212,7 +212,7 @@ if not valid_config(): pytest.xfail("failing configuration (but should work)") # or - pytest.skipif("unsupported configuration") + pytest.skip("unsupported configuration") Skipping on a missing import dependency https://bitbucket.org/hpk42/pytest/commits/248fda37abc6/ Changeset: 248fda37abc6 User: hpk42 Date: 2014-01-10 10:44:12 Summary: Merged in lakka/pytest//minor-doc-fix-in-skippingtxt-also-submi-1387492852421 (pull request #94) Minor doc fix in skipping.txt. Also submitted at Github before I realised that this was the master repo. Will close over there. Affected #: 1 file diff -r d76058834af217b7d319bac2549d6f8841564ef9 -r 248fda37abc658629f163cb218fa7b147b2cff6c doc/en/skipping.txt --- a/doc/en/skipping.txt +++ b/doc/en/skipping.txt @@ -212,7 +212,7 @@ if not valid_config(): pytest.xfail("failing configuration (but should work)") # or - pytest.skipif("unsupported configuration") + pytest.skip("unsupported configuration") Skipping on a missing import dependency Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Fri Jan 10 11:01:01 2014 From: notifications at travis-ci.org (Travis CI) Date: Fri, 10 Jan 2014 10:01:01 +0000 Subject: [Pytest-commit] [Broken] hpk42/pytest#74 (master - 3e1a7d5) Message-ID: <52cfc4dd3a98_212ebc37827e@1df0e434-7861-4657-9bd7-8f2512d948e0.mail> Build Update for hpk42/pytest ------------------------------------- Build: #74 Status: Broken Duration: 10 minutes and 57 seconds Commit: 3e1a7d5 (master) Author: holger krekel Message: Merged in lakka/pytest//minor-doc-fix-in-skippingtxt-also-submi-1387492852421 (pull request #94) Minor doc fix in skipping.txt. Also submitted at Github before I realised that this was the master repo. Will close over there. View the changeset: https://github.com/hpk42/pytest/compare/76e6ff91b2c3...3e1a7d58b356 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/16711450 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Sat Jan 11 10:48:14 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 11 Jan 2014 09:48:14 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: remove build status that shows on pypi -- doesn't make sense because it shows the current trunk, not the released version. And start a new doc/en/status.txt Message-ID: <20140111094814.7980.38150@app12.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/0bf4880a178d/ Changeset: 0bf4880a178d User: hpk42 Date: 2014-01-11 10:46:07 Summary: remove build status that shows on pypi -- doesn't make sense because it shows the current trunk, not the released version. And start a new doc/en/status.txt Affected #: 2 files diff -r 248fda37abc658629f163cb218fa7b147b2cff6c -r 0bf4880a178da71d44ba91d844e68165c83f2562 README.rst --- a/README.rst +++ b/README.rst @@ -22,9 +22,6 @@ - many `external plugins `_. -.. image:: https://secure.travis-ci.org/hpk42/pytest.png - :target: http://travis-ci.org/hpk42/pytest - A simple example for a test:: # content of test_module.py diff -r 248fda37abc658629f163cb218fa7b147b2cff6c -r 0bf4880a178da71d44ba91d844e68165c83f2562 doc/en/status.txt --- /dev/null +++ b/doc/en/status.txt @@ -0,0 +1,8 @@ +pytest development status +================================ + +github triggered travis: + +.. image:: https://secure.travis-ci.org/hpk42/pytest.png + :target: http://travis-ci.org/hpk42/pytest + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Sat Jan 11 11:01:00 2014 From: notifications at travis-ci.org (Travis CI) Date: Sat, 11 Jan 2014 10:01:00 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#75 (master - 482e6bd) Message-ID: <52d1165c182b8_2320627258a@7f910608-5424-46f9-a1c1-1aecd43173b4.mail> Build Update for hpk42/pytest ------------------------------------- Build: #75 Status: Still Failing Duration: 11 minutes and 46 seconds Commit: 482e6bd (master) Author: holger krekel Message: remove build status that shows on pypi -- doesn't make sense because it shows the current trunk, not the released version. And start a new doc/en/status.txt View the changeset: https://github.com/hpk42/pytest/compare/3e1a7d58b356...482e6bd97639 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/16769782 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Sun Jan 12 17:33:04 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 12 Jan 2014 16:33:04 -0000 Subject: [Pytest-commit] commit/tox: 3 new changesets Message-ID: <20140112163304.32180.99028@app06.ash-private.bitbucket.org> 3 new commits in tox: https://bitbucket.org/hpk42/tox/commits/228071477cfb/ Changeset: 228071477cfb User: ionelmc Date: 2014-01-11 16:59:44 Summary: Change tox to use the virtualenv bin instead of invoking it with the current interpreter. Virtualenv might have been installed with a completely different interpreter (and might not work at all!) or it could have other issues caused by invoking the module directly (virtualenv 1.11 known to break). Also add a `virtualenvbin` config option in case it need overriding. Affected #: 3 files diff -r 4542c26e2a8ad4f1708abe8a2a2024a4825b6e3f -r 228071477cfbc350fb2e0a437f2ebd5e52f55ee1 tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -48,11 +48,8 @@ l = mocksession._pcalls assert len(l) >= 1 args = l[0].args - assert "virtualenv" in str(args[1]) + assert str(args[0]).endswith("virtualenv") if sys.platform != "win32": - # realpath is needed for stuff like the debian symlinks - assert py.path.local(sys.executable).realpath() \ - == py.path.local(args[0]).realpath() #assert Envconfig.toxworkdir in args assert venv.getcommandpath("easy_install", cwd=py.path.local()) interp = venv._getliveconfig().python @@ -321,7 +318,7 @@ l = mocksession._pcalls assert len(l) == 1 args = l[0].args - assert str(args[1]).endswith('virtualenv.py') + assert str(args[0]).endswith('virtualenv') l[:] = [] action = mocksession.newaction(venv, "hello") venv._install(["hello"], action=action) diff -r 4542c26e2a8ad4f1708abe8a2a2024a4825b6e3f -r 228071477cfbc350fb2e0a437f2ebd5e52f55ee1 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -357,6 +357,7 @@ ixserver = None name = self._replace_forced_dep(name, config) vc.deps.append(DepConfig(name, ixserver)) + vc.virtualenvbin = reader.getdefault(section, "virtualenvbin", "virtualenv") vc.distribute = reader.getbool(section, "distribute", False) vc.sitepackages = self.config.option.sitepackages or \ reader.getbool(section, "sitepackages", False) @@ -734,4 +735,3 @@ if 'HUDSON_URL' in os.environ: return 'jenkins' return None - diff -r 4542c26e2a8ad4f1708abe8a2a2024a4825b6e3f -r 228071477cfbc350fb2e0a437f2ebd5e52f55ee1 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -178,13 +178,8 @@ if action is None: action = self.session.newaction(self, "create") - interpreters = self.envconfig.config.interpreters config_interpreter = self.getsupportedinterpreter() - info = interpreters.get_info(executable=config_interpreter) - f, path, _ = py.std.imp.find_module("virtualenv") - f.close() - venvscript = path.rstrip("co") - args = [config_interpreter, str(venvscript)] + args = [self.envconfig.virtualenvbin] if self.envconfig.distribute: args.append("--distribute") else: https://bitbucket.org/hpk42/tox/commits/f54ba7b918e8/ Changeset: f54ba7b918e8 User: ionelmc Date: 2014-01-11 17:09:50 Summary: Improve assertion to pass on windows. Affected #: 1 file diff -r 228071477cfbc350fb2e0a437f2ebd5e52f55ee1 -r f54ba7b918e8059fafd341395e32472a8ae3720e tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -48,7 +48,7 @@ l = mocksession._pcalls assert len(l) >= 1 args = l[0].args - assert str(args[0]).endswith("virtualenv") + assert "virtualenv" in str(args[0]) if sys.platform != "win32": #assert Envconfig.toxworkdir in args assert venv.getcommandpath("easy_install", cwd=py.path.local()) https://bitbucket.org/hpk42/tox/commits/0b3ce1895d03/ Changeset: 0b3ce1895d03 User: ionelmc Date: 2014-01-12 14:18:23 Summary: Remove virtualenvbin config option. Affected #: 2 files diff -r f54ba7b918e8059fafd341395e32472a8ae3720e -r 0b3ce1895d0387e4fe64afc3dd337e11d6256def tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -357,7 +357,6 @@ ixserver = None name = self._replace_forced_dep(name, config) vc.deps.append(DepConfig(name, ixserver)) - vc.virtualenvbin = reader.getdefault(section, "virtualenvbin", "virtualenv") vc.distribute = reader.getbool(section, "distribute", False) vc.sitepackages = self.config.option.sitepackages or \ reader.getbool(section, "sitepackages", False) diff -r f54ba7b918e8059fafd341395e32472a8ae3720e -r 0b3ce1895d0387e4fe64afc3dd337e11d6256def tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -179,7 +179,7 @@ action = self.session.newaction(self, "create") config_interpreter = self.getsupportedinterpreter() - args = [self.envconfig.virtualenvbin] + args = ['virtualenv'] if self.envconfig.distribute: args.append("--distribute") else: Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sun Jan 12 18:46:57 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 12 Jan 2014 17:46:57 -0000 Subject: [Pytest-commit] commit/tox: hpk42: add changelog entry and extend list of contributors Message-ID: <20140112174657.8368.50817@app08.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/ab3ca2815135/ Changeset: ab3ca2815135 User: hpk42 Date: 2014-01-12 18:46:49 Summary: add changelog entry and extend list of contributors Affected #: 2 files diff -r 0b3ce1895d0387e4fe64afc3dd337e11d6256def -r ab3ca2815135d40e27f17c6fdfe616cbbdecd50a CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -24,7 +24,8 @@ - fix issue126: depend on virtualenv>=1.10.1 so that we can rely (hopefully) on a pip version which supports --pre. (tox by default - uses to --pre). + uses to --pre). also merged in PR84 so that we now call "virtualenv" + directly instead of looking up interpreters. Thanks Ionel Maries Cristian. - fix issue130: you can now set install_command=easy_install {opts} {packages} and expect it to work for repeated tox runs (previously it only worked diff -r 0b3ce1895d0387e4fe64afc3dd337e11d6256def -r ab3ca2815135d40e27f17c6fdfe616cbbdecd50a CONTRIBUTORS --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -12,3 +12,13 @@ Philip Thiem Monty Taylor Bruno Oliveira +Ionel Maries Cristian +Anatoly techntonik +Matt Jeffery +Chris Jerdonek +Ronald Evers +Carl Meyer +Anthon van der Neuth +Matt Good +Mattieu Agopian +Asmund Grammeltwedt Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Tue Jan 14 21:46:32 2014 From: issues-reply at bitbucket.org (Marcus Smith) Date: Tue, 14 Jan 2014 20:46:32 -0000 Subject: [Pytest-commit] Issue #144: virtualenv 1.11 does not provide "pip-script.py" under windows (hpk42/tox) Message-ID: <20140114204632.23911.51157@app07.ash-private.bitbucket.org> New issue 144: virtualenv 1.11 does not provide "pip-script.py" under windows https://bitbucket.org/hpk42/tox/issue/144/virtualenv-111-does-not-provide-pip Marcus Smith: see comment here https://github.com/pypa/virtualenv/issues/539#issuecomment-32258951 with virtualenv-1.11, under windows, there won't be a "pip-script.py" to call, just "pip.exe" cc @pmoore From issues-reply at bitbucket.org Wed Jan 15 05:01:52 2014 From: issues-reply at bitbucket.org (Ben Darnell) Date: Wed, 15 Jan 2014 04:01:52 -0000 Subject: [Pytest-commit] Issue #145: 'commands' variable cannot be substituted (hpk42/tox) Message-ID: <20140115040152.32009.28817@app05.ash-private.bitbucket.org> New issue 145: 'commands' variable cannot be substituted https://bitbucket.org/hpk42/tox/issue/145/commands-variable-cannot-be-substituted Ben Darnell: Using substitution on the 'commands' variable does not appear to work - the substituted string is passed as a single token to the subprocess module. I would expect the splitting to be done after performing the substitution. Stripped down example: ``` [tox] envlist=py26, py27, py32, py33 [testenv] commands = python -c 'print "py2"' [testenv:py32] commands = python -c 'print("py3")' [testenv:py33] commands = {[testenv:py32]commands} ``` Output: ``` GLOB sdist-make: /private/tmp/toxtest/setup.py py26 inst-nodeps: /private/tmp/toxtest/.tox/dist/UNKNOWN-0.0.0.zip py26 runtests: commands[0] | python -c print "py2" py2 py27 recreate: /private/tmp/toxtest/.tox/py27 py27 inst: /private/tmp/toxtest/.tox/dist/UNKNOWN-0.0.0.zip py27 runtests: commands[0] | python -c print "py2" py2 py32 inst-nodeps: /private/tmp/toxtest/.tox/dist/UNKNOWN-0.0.0.zip py32 runtests: commands[0] | python -c print("py3") py3 py33 inst-nodeps: /private/tmp/toxtest/.tox/dist/UNKNOWN-0.0.0.zip py33 runtests: commands[0] | python -c 'print("py3")' ERROR: InvocationError: could not find executable 'python -c \'print("py3")\'' ___________________________________ summary ____________________________________ py26: commands succeeded py27: commands succeeded py32: commands succeeded ERROR: py33: commands failed ``` From issues-reply at bitbucket.org Wed Jan 15 17:13:24 2014 From: issues-reply at bitbucket.org (=?utf-8?q?Jurko_Gospodneti=C4=87?=) Date: Wed, 15 Jan 2014 16:13:24 -0000 Subject: [Pytest-commit] Issue #422: Document ExceptionInfo.value (hpk42/pytest) Message-ID: <20140115161324.10198.7030@app18.ash-private.bitbucket.org> New issue 422: Document ExceptionInfo.value https://bitbucket.org/hpk42/pytest/issue/422/document-exceptioninfovalue Jurko Gospodneti?: I have not been able to find any documentation on how the actual exception raised during a pytest.raises() call can be accessed. A little research points to the ExceptionInfo.value attribute. The docs should be updated to describe the ExceptionInfo.value attribute. They should also be updated to include a note, similar to one already present in regular Python documentation, about having to explicitly delete all local references to the received ExceptionInfo instance. Those references are part of a reference cycle (exception --> stack frame raising the exception --> current stack frame --> locals --> exception_info --> exception) which, unless explicitly broken, will cause all objects in that cycle not to be garbage collected until potentially a much later time. YMMV, but this increases the test code memory footprint and possibly slows down the tests in case they can not finish until some finalizer code has run. Hope this helps. Best regards, Jurko Gospodneti? From issues-reply at bitbucket.org Thu Jan 16 17:15:36 2014 From: issues-reply at bitbucket.org (Ldiary Translations) Date: Thu, 16 Jan 2014 16:15:36 -0000 Subject: [Pytest-commit] Issue #423: Consecutive pytest.mark.skipif inside pytest.mark.parameterize (hpk42/pytest) Message-ID: <20140116161536.23703.66687@app01.ash-private.bitbucket.org> New issue 423: Consecutive pytest.mark.skipif inside pytest.mark.parameterize https://bitbucket.org/hpk42/pytest/issue/423/consecutive-pytestmarkskipif-inside Ldiary Translations: Given the test module below which was derived from the documentation example: http://pytest.org/latest/parametrize.html#pytest-mark-parametrize-parametrizing-test-functions ``` #!python import pytest flag = [] @pytest.mark.default @pytest.mark.parametrize("my_input,expected", [ ("3+5", 8), ("2+4", 6), ("6*9", 42), ]) def test_default_example(my_input, expected): assert eval(my_input) == expected @pytest.mark.skipsecond @pytest.mark.parametrize("my_input,expected", [ ("3+5", "Failed"), pytest.mark.skipif("flag == []", ("2+4", 6)), ("6*9", 42), ]) def test_skip_second(my_input, expected): print("\nBefore clearing flag: ", flag) while len(flag) > 0: flag.pop() print("After clearing flag: ", flag) assert eval(my_input) == expected flag.append("Previous Test Passed") @pytest.mark.skipthird @pytest.mark.parametrize("my_input,expected", [ ("3+5", 8), ("2+4", "Failed"), pytest.mark.skipif("flag == []", ("6*9", 42)), ]) def test_skip_third(my_input, expected): print("\nBefore clearing flag: ", flag) while len(flag) > 0: flag.pop() print("After clearing flag: ", flag) assert eval(my_input) == expected flag.append("Previous Test Passed") @pytest.mark.skipsecondthird @pytest.mark.parametrize("my_input,expected", [ ("3+5", 8), pytest.mark.skipif("flag == []", ("2+4", "Failed")), pytest.mark.skipif("flag == []", ("6*9", 42)), ]) def test_skip_second_third(my_input, expected): print("\nBefore clearing flag: ", flag) while len(flag) > 0: flag.pop() print("After clearing flag: ", flag) assert eval(my_input) == expected flag.append("Previous Test Passed") ``` The test marks "default", "skipsecond" and "skipthird" works as expected, but the test mark "skipsecondthird" has strange behaviour. We can't understand why when the "skipsecondthird" test mark is executed like below, the last test was still executed three times. We are expecting that the first test execution will be PASSED, the second test execution will FAILED, and the third execution will be SKIPPED; but it wasn't. Are consecutive skipif inside parameterize supported on the first place? Or is this a bug? $ py.test -svm skipsecondthird ========== test session starts ============================= platform linux -- Python 3.3.3 -- pytest-2.5.0 -- /home/ldiary/py3env/bin/python3 SecondSkipInParameterized.py:47: test_skip_second_third[3+5-8] Before clearing flag: [] After clearing flag: [] PASSED SecondSkipInParameterized.py:47: test_skip_second_third[2+4-Failed] Before clearing flag: ['Previous Test Passed'] After clearing flag: [] FAILED SecondSkipInParameterized.py:47: test_skip_second_third[6*9-42] Before clearing flag: [] After clearing flag: [] FAILED =========== 2 failed, 1 passed, 118 deselected in 0.37 seconds=============== From issues-reply at bitbucket.org Thu Jan 16 20:55:37 2014 From: issues-reply at bitbucket.org (Trevor Bekolay) Date: Thu, 16 Jan 2014 19:55:37 -0000 Subject: [Pytest-commit] Issue #424: Running on multiple CPUs significantly slower (hpk42/pytest) Message-ID: <20140116195537.9284.96536@app08.ash-private.bitbucket.org> New issue 424: Running on multiple CPUs significantly slower https://bitbucket.org/hpk42/pytest/issue/424/running-on-multiple-cpus-significantly Trevor Bekolay: Before today, with `pytest-xdist`, `py.test -n X` would result in significant speedups. Today, it's significantly slower. ``` $ py.test ================================== test session starts =========================== platform linux2 -- Python 2.7.6 -- pytest-2.5.1 plugins: xdist collected 81 items ................................................................................. =============================== 81 passed in 32.63 seconds ======================= $ py.test -n 2 ================================== test session starts ============================ platform linux2 -- Python 2.7.6 -- pytest-2.5.1 plugins: xdist gw0 [81] / gw1 [81] scheduling tests via LoadScheduling ................................................................................. ============================== 81 passed in 252.04 seconds ======================= ``` The only thing that's changed since yesterday is that I did an apt update that installed a new version of Python 2.7. I'm on Debian unstable (sid). All of the Python2.7 packages were updated from version 2.7.6-4 to 2.7.6-5. Is it possible that one of those updates broke thing? I recreated my virtualenvs, but I'm still experiencing slowdown. From commits-noreply at bitbucket.org Sat Jan 18 14:51:13 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 18 Jan 2014 13:51:13 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20140118135113.9693.72784@app02.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/5cc8f7cc8c26/ Changeset: 5cc8f7cc8c26 User: jurko Date: 2014-01-18 10:40:20 Summary: trim trailing spaces Affected #: 1 file diff -r 8afb9592588abefd3ffe49d24811acf18deadfb1 -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -307,7 +307,7 @@ '*ERROR*', ]) assert result.ret == 4 # usage error only if item not found - + def test_namespace_import_doesnt_confuse_import_hook(self, testdir): # Ref #383. Python 3.3's namespace package messed with our import hooks # Importing a module that didn't exist, even if the ImportError was @@ -319,7 +319,7 @@ except ImportError: # We handle the import error gracefully here pass - + def test_whatever(): pass """) https://bitbucket.org/hpk42/pytest/commits/2c04f47decfa/ Changeset: 2c04f47decfa User: jurko Date: 2014-01-18 12:31:33 Summary: replace py.test module references with pytest The only remaining 'py.test' references are: * those referring to the 'py.test' executable * those in code explicitly testing py.test/pytest module compatibility * those in old CHANGES documentation * those in documentation generated based on external data * those in seemingly unfinished & unmaintained Japanese documentation Minor stylistic changes and typo corrections made to documentation next to several applied py.test --> pytest content changes. Affected #: 66 files diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -122,8 +122,8 @@ ------------------------------------------------------- tags: feature -- introduce py.test.mark.nocollect for not considering a function for - test collection at all. maybe also introduce a py.test.mark.test to +- introduce pytest.mark.nocollect for not considering a function for + test collection at all. maybe also introduce a pytest.mark.test to explicitely mark a function to become a tested one. Lookup JUnit ways of tagging tests. @@ -135,18 +135,18 @@ a pytest.mark.importorskip so that the test count is more correct. -introduce py.test.mark.platform +introduce pytest.mark.platform ------------------------------------------------------- tags: feature Introduce nice-to-spell platform-skipping, examples: - @py.test.mark.platform("python3") - @py.test.mark.platform("not python3") - @py.test.mark.platform("win32 and not python3") - @py.test.mark.platform("darwin") - @py.test.mark.platform("not (jython and win32)") - @py.test.mark.platform("not (jython and win32)", xfail=True) + @pytest.mark.platform("python3") + @pytest.mark.platform("not python3") + @pytest.mark.platform("win32 and not python3") + @pytest.mark.platform("darwin") + @pytest.mark.platform("not (jython and win32)") + @pytest.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 @@ -181,8 +181,8 @@ allow to name conftest.py files (in sub directories) that should be imported early, as to include command line options. -improve central py.test ini file ----------------------------------- +improve central pytest ini file +------------------------------- tags: feature introduce more declarative configuration options: @@ -196,7 +196,7 @@ ---------------------------------- tags: feature -- logo py.test +- logo pytest - examples for unittest or functional testing - resource management for functional testing - patterns: page object @@ -205,17 +205,17 @@ -------------------------------------------------------- tags: bug -With 1.1.1 py.test fails at least on windows if an import +With 1.1.1 pytest fails at least on windows if an import is relative and compared against an absolute conftest.py path. Normalize. -consider globals: py.test.ensuretemp and config +consider globals: pytest.ensuretemp and config -------------------------------------------------------------- tags: experimental-wish -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 +consider deprecating pytest.ensuretemp and pytest.config +to further reduce pytest globality. Also consider +having pytest.config and ensuretemp coming from a plugin rather than being there from the start. @@ -223,7 +223,7 @@ ----------------------------------------- tags: wish -py.test could call a new pytest_addsyspath() in order to systematically +pytest 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. @@ -232,11 +232,11 @@ -deprecate global py.test.config usage +deprecate global pytest.config usage ---------------------------------------------------------------- tags: feature -py.test.ensuretemp and py.test.config are probably the last +pytest.ensuretemp and pytest.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 diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 README.rst --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ Issues: https://bitbucket.org/hpk42/pytest/issues?status=open -The ``py.test`` testing tool makes it easy to write small tests, yet +The ``pytest`` testing tool makes it easy to write small tests, yet scales to support complex functional testing. It provides - `auto-discovery @@ -14,7 +14,7 @@ - detailed info on failing `assert statements `_ (no need to remember ``self.assert*`` names) - `modular fixtures `_ for managing small or parametrized long-lived test resources. -- multi-paradigm support: you can use ``py.test`` to run test suites based +- multi-paradigm support: you can use ``pytest`` to run test suites based on `unittest `_ (or trial), `nose `_ - single-source compatibility to Python2.4 all the way up to Python3.3, diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/assertion/rewrite.py --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -15,7 +15,7 @@ from _pytest.assertion import util -# py.test caches rewritten pycs in __pycache__. +# pytest caches rewritten pycs in __pycache__. if hasattr(imp, "get_tag"): PYTEST_TAG = imp.get_tag() + "-PYTEST" else: @@ -102,7 +102,7 @@ # the most magical part of the process: load the source, rewrite the # asserts, and load the rewritten source. We also cache the rewritten # module code in a special pyc. We must be aware of the possibility of - # concurrent py.test processes rewriting and loading pycs. To avoid + # concurrent pytest processes rewriting and loading pycs. To avoid # tricky race conditions, we maintain the following invariant: The # cached pyc is always a complete, valid pyc. Operations on it must be # atomic. POSIX's atomic rename comes in handy. @@ -290,7 +290,7 @@ os.rename(proc_pyc, pyc) def _read_pyc(source, pyc): - """Possibly read a py.test pyc containing rewritten code. + """Possibly read a pytest pyc containing rewritten code. Return rewritten code if successful or None if not. """ diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -1,6 +1,7 @@ """ command line options, ini-file and conftest.py processing. """ import py +import pytest import sys, os from _pytest import hookspec # the extension point definitions from _pytest.core import PluginManager @@ -22,7 +23,7 @@ main = staticmethod(main) class UsageError(Exception): - """ error in py.test usage or invocation""" + """ error in pytest usage or invocation""" _preinit = [] @@ -225,7 +226,7 @@ help = attrs['help'] if '%default' in help: py.std.warnings.warn( - 'py.test now uses argparse. "%default" should be' + 'pytest now uses argparse. "%default" should be' ' changed to "%(default)s" ', FutureWarning, stacklevel=3) @@ -448,7 +449,7 @@ class Conftest(object): """ the single place for accessing values and interacting - towards conftest modules from py.test objects. + towards conftest modules from pytest objects. """ def __init__(self, onimport=None, confcutdir=None): self._path2confmods = {} @@ -808,7 +809,7 @@ def getvalueorskip(self, name, path=None): """ (deprecated) return getvalue(name) or call - py.test.skip if no value exists. """ + pytest.skip if no value exists. """ __tracebackhide__ = True try: val = self.getvalue(name, path) @@ -816,7 +817,7 @@ raise KeyError(name) return val except KeyError: - py.test.skip("no %r value found" %(name,)) + pytest.skip("no %r value found" %(name,)) def exists(path, ignore=EnvironmentError): try: diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/core.py --- a/_pytest/core.py +++ b/_pytest/core.py @@ -4,6 +4,7 @@ import sys import inspect import py +import pytest assert py.__version__.split(".")[:2] >= ['1', '4'], ("installation problem: " "%s is too old, remove or upgrade 'py'" % (py.__version__)) @@ -136,7 +137,7 @@ def skipifmissing(self, name): if not self.hasplugin(name): - py.test.skip("plugin %r is missing" % name) + pytest.skip("plugin %r is missing" % name) def hasplugin(self, name): return bool(self.getplugin(name)) @@ -220,9 +221,9 @@ raise except: e = py.std.sys.exc_info()[1] - if not hasattr(py.test, 'skip'): + if not hasattr(pytest, 'skip'): raise - elif not isinstance(e, py.test.skip.Exception): + elif not isinstance(e, pytest.skip.Exception): raise self._hints.append("skipped plugin %r: %s" %((modname, e.msg))) else: diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/genscript.py --- a/_pytest/genscript.py +++ b/_pytest/genscript.py @@ -1,4 +1,4 @@ -""" generate a single-file self-contained version of py.test """ +""" generate a single-file self-contained version of pytest """ import py import sys @@ -55,7 +55,7 @@ group = parser.getgroup("debugconfig") group.addoption("--genscript", action="store", default=None, dest="genscript", metavar="path", - help="create standalone py.test script at given target path.") + help="create standalone pytest script at given target path.") def pytest_cmdline_main(config): genscript = config.getvalue("genscript") @@ -70,7 +70,7 @@ "or below due to 'argparse' dependency. Use python2.6 " "to generate a python2.5/6 compatible script", red=True) script = generate_script( - 'import py; raise SystemExit(py.test.cmdline.main())', + 'import pytest; raise SystemExit(pytest.cmdline.main())', deps, ) genscript = py.path.local(genscript) diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -46,7 +46,7 @@ def pytest_cmdline_main(config): if config.option.version: p = py.path.local(pytest.__file__) - sys.stderr.write("This is py.test version %s, imported from %s\n" % + sys.stderr.write("This is pytest version %s, imported from %s\n" % (pytest.__version__, p)) plugininfo = getpluginversioninfo(config) if plugininfo: diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/hookspec.py --- a/_pytest/hookspec.py +++ b/_pytest/hookspec.py @@ -11,8 +11,8 @@ def pytest_namespace(): """return dict of name->object to be made globally available in - the py.test/pytest namespace. This hook is called before command - line options are parsed. + the pytest namespace. This hook is called before command line options + are parsed. """ def pytest_cmdline_parse(pluginmanager, args): diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -63,7 +63,7 @@ return dict(collect=collect) def pytest_configure(config): - py.test.config = config # compatibiltiy + pytest.config = config # compatibiltiy if config.option.exitfirst: config.option.maxfail = 1 diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -157,10 +157,10 @@ class MarkGenerator: """ Factory for :class:`MarkDecorator` objects - exposed as - a ``py.test.mark`` singleton instance. Example:: + a ``pytest.mark`` singleton instance. Example:: import py - @py.test.mark.slowtest + @pytest.mark.slowtest def test_function(): pass @@ -198,8 +198,8 @@ :ref:`retrieved by hooks as item keywords `. MarkDecorator instances are often created like this:: - mark1 = py.test.mark.NAME # simple MarkDecorator - mark2 = py.test.mark.NAME(name1=value) # parametrized MarkDecorator + mark1 = pytest.mark.NAME # simple MarkDecorator + mark2 = pytest.mark.NAME(name1=value) # parametrized MarkDecorator and can then be applied as decorators to test functions:: diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/nose.py --- a/_pytest/nose.py +++ b/_pytest/nose.py @@ -8,7 +8,7 @@ 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 pytest.skip one call2 = call.__class__(lambda: pytest.skip(str(call.excinfo.value)), call.when) call.excinfo = call2.excinfo diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -1,4 +1,4 @@ -""" (disabled by default) support for testing py.test and py.test plugins. """ +""" (disabled by default) support for testing pytest and pytest plugins. """ import py, pytest import sys, os @@ -137,7 +137,7 @@ break print_("NONAMEMATCH", name, "with", call) else: - py.test.fail("could not find %r check %r" % (name, check)) + pytest.fail("could not find %r check %r" % (name, check)) def popcall(self, name): __tracebackhide__ = True @@ -147,7 +147,7 @@ return call lines = ["could not find call %r, in:" % (name,)] lines.extend([" %s" % str(x) for x in self.calls]) - py.test.fail("\n".join(lines)) + pytest.fail("\n".join(lines)) def getcall(self, name): l = self.getcalls(name) @@ -472,7 +472,7 @@ # becaue on windows the script is e.g. a py.test.exe return (py.std.sys.executable, _pytest_fullpath,) # noqa else: - py.test.skip("cannot run %r with --no-tools-on-path" % scriptname) + pytest.skip("cannot run %r with --no-tools-on-path" % scriptname) def runpython(self, script, prepend=True): if prepend: @@ -509,14 +509,14 @@ def spawn_pytest(self, string, expect_timeout=10.0): if self.request.config.getvalue("notoolsonpath"): - py.test.skip("--no-tools-on-path prevents running pexpect-spawn tests") + pytest.skip("--no-tools-on-path prevents running pexpect-spawn tests") basetemp = self.tmpdir.mkdir("pexpect") invoke = " ".join(map(str, self._getpybinargs("py.test"))) cmd = "%s --basetemp=%s %s" % (invoke, basetemp, string) return self.spawn(cmd, expect_timeout=expect_timeout) def spawn(self, cmd, expect_timeout=10.0): - pexpect = py.test.importorskip("pexpect", "3.0") + pexpect = pytest.importorskip("pexpect", "3.0") if hasattr(sys, 'pypy_version_info') and '64' in py.std.platform.machine(): pytest.skip("pypy-64 bit not supported") if sys.platform == "darwin": @@ -688,4 +688,4 @@ show(" and:", repr(nextline)) extralines.append(nextline) else: - py.test.fail("remains unmatched: %r, see stderr" % (line,)) + pytest.fail("remains unmatched: %r, see stderr" % (line,)) diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -485,7 +485,7 @@ fin = getattr(self.obj, 'teardown_module', None) if fin is not None: #XXX: nose compat hack, move to nose plugin - # if it takes a positional arg, its probably a py.test style one + # if it takes a positional arg, its probably a pytest style one # so we pass the current module object if inspect.getargspec(fin)[0]: finalizer = lambda: fin(self.obj) @@ -1011,7 +1011,7 @@ return issubclass(self.excinfo.type, self.ExpectedException) # -# the basic py.test Function item +# the basic pytest Function item # class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr): @@ -1225,7 +1225,7 @@ on all function invocations. :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object - created by a call to ``py.test.mark.NAME(...)``. + created by a call to ``pytest.mark.NAME(...)``. """ try: self.node.keywords[marker.markname] = marker diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -1,6 +1,8 @@ """ basic collect and runtest protocol implementations """ -import py, sys +import py +import pytest +import sys from time import time from py._code.code import TerminalRepr @@ -196,7 +198,7 @@ if not isinstance(excinfo, py.code.ExceptionInfo): outcome = "failed" longrepr = excinfo - elif excinfo.errisinstance(py.test.skip.Exception): + elif excinfo.errisinstance(pytest.skip.Exception): outcome = "skipped" r = excinfo._getreprcrash() longrepr = (str(r.path), r.lineno, r.message) @@ -418,7 +420,7 @@ __module__ = 'builtins' class Failed(OutcomeException): - """ raised from an explicit call to py.test.fail() """ + """ raised from an explicit call to pytest.fail() """ __module__ = 'builtins' class Exit(KeyboardInterrupt): @@ -438,7 +440,7 @@ def skip(msg=""): """ skip an executing test with the given message. Note: it's usually - better to use the py.test.mark.skipif marker to declare a test to be + better to use the pytest.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. """ diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/skipping.py --- a/_pytest/skipping.py +++ b/_pytest/skipping.py @@ -37,7 +37,7 @@ return dict(xfail=xfail) class XFailed(pytest.fail.Exception): - """ raised from an explicit call to py.test.xfail() """ + """ raised from an explicit call to pytest.xfail() """ def xfail(reason=""): """ xfail an executing test or setup functions with the given reason.""" @@ -129,7 +129,7 @@ return evalskip = MarkEvaluator(item, 'skipif') if evalskip.istrue(): - py.test.skip(evalskip.getexplanation()) + pytest.skip(evalskip.getexplanation()) item._evalxfail = MarkEvaluator(item, 'xfail') check_xfail_no_run(item) @@ -141,7 +141,7 @@ evalxfail = item._evalxfail if evalxfail.istrue(): if not evalxfail.get('run', True): - py.test.xfail("[NOTRUN] " + evalxfail.getexplanation()) + pytest.xfail("[NOTRUN] " + evalxfail.getexplanation()) def pytest_runtest_makereport(__multicall__, item, call): if not isinstance(item, pytest.Function): @@ -150,16 +150,16 @@ if hasattr(item, '_unexpectedsuccess'): rep = __multicall__.execute() if rep.when == "call": - # we need to translate into how py.test encodes xpass + # we need to translate into how pytest encodes xpass rep.wasxfail = "reason: " + repr(item._unexpectedsuccess) rep.outcome = "failed" return rep if not (call.excinfo and - call.excinfo.errisinstance(py.test.xfail.Exception)): + call.excinfo.errisinstance(pytest.xfail.Exception)): evalxfail = getattr(item, '_evalxfail', None) if not evalxfail: return - if call.excinfo and call.excinfo.errisinstance(py.test.xfail.Exception): + if call.excinfo and call.excinfo.errisinstance(pytest.xfail.Exception): if not item.config.getvalue("runxfail"): rep = __multicall__.execute() rep.wasxfail = "reason: " + call.excinfo.value.msg diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 _pytest/terminal.py --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -259,7 +259,7 @@ if hasattr(sys, 'pypy_version_info'): verinfo = ".".join(map(str, sys.pypy_version_info[:3])) msg += "[pypy-%s-%s]" % (verinfo, sys.pypy_version_info[3]) - msg += " -- pytest-%s" % (py.test.__version__) + msg += " -- pytest-%s" % (pytest.__version__) if self.verbosity > 0 or self.config.option.debug or \ getattr(self.config.option, 'pastebin', None): msg += " -- " + str(sys.executable) diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 bench/bench.py --- a/bench/bench.py +++ b/bench/bench.py @@ -2,10 +2,10 @@ if __name__ == '__main__': import cProfile - import py + import pytest import pstats script = sys.argv[1] if len(sys.argv) > 1 else "empty.py" - stats = cProfile.run('py.test.cmdline.main([%r])' % script, 'prof') + stats = cProfile.run('pytest.cmdline.main([%r])' % script, 'prof') p = pstats.Stats("prof") p.strip_dirs() p.sort_stats('cumulative') diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/apiref.txt --- a/doc/en/apiref.txt +++ b/doc/en/apiref.txt @@ -1,7 +1,7 @@ .. _apiref: -py.test reference documentation +pytest reference documentation ================================================ .. toctree:: diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/assert.txt --- a/doc/en/assert.txt +++ b/doc/en/assert.txt @@ -10,7 +10,7 @@ Asserting with the ``assert`` statement --------------------------------------------------------- -``py.test`` allows you to use the standard python ``assert`` for verifying +``pytest`` allows you to use the standard python ``assert`` for verifying expectations and values in Python tests. For example, you can write the following:: @@ -28,21 +28,21 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items - + test_assert1.py F - + ================================= FAILURES ================================= ______________________________ test_function _______________________________ - + def test_function(): > assert f() == 4 E assert 3 == 4 E + where 3 = f() - + test_assert1.py:5: AssertionError ========================= 1 failed in 0.01 seconds ========================= -py.test has support for showing the values of the most common subexpressions +``pytest`` has support for showing the values of the most common subexpressions including calls, attributes, comparisons, and binary and unary operators. (See :ref:`tbreportdemo`). This allows you to use the idiomatic python constructs without boilerplate code while not losing @@ -102,7 +102,7 @@ .. versionadded:: 2.0 -py.test has rich support for providing context-sensitive information +``pytest`` has rich support for providing context-sensitive information when it encounters comparisons. For example:: # content of test_assert2.py @@ -118,12 +118,12 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items - + test_assert2.py F - + ================================= FAILURES ================================= ___________________________ test_set_comparison ____________________________ - + def test_set_comparison(): set1 = set("1308") set2 = set("8035") @@ -133,7 +133,7 @@ E '1' E Extra items in the right set: E '5' - + test_assert2.py:5: AssertionError ========================= 1 failed in 0.01 seconds ========================= @@ -175,21 +175,21 @@ f2 = Foo(2) assert f1 == f2 -you can run the test module and get the custom output defined in +you can run the test module and get the custom output defined in the conftest file:: $ py.test -q test_foocompare.py F ================================= FAILURES ================================= _______________________________ test_compare _______________________________ - + def test_compare(): f1 = Foo(1) f2 = Foo(2) > assert f1 == f2 E assert Comparing Foo instances: E vals: 1 != 2 - + test_foocompare.py:8: AssertionError 1 failed in 0.01 seconds @@ -205,33 +205,33 @@ Reporting details about a failing assertion is achieved either by rewriting assert statements before they are run or re-evaluating the assert expression and recording the intermediate values. Which technique is used depends on the -location of the assert, py.test's configuration, and Python version being used -to run py.test. Note that for assert statements with a manually provided +location of the assert, ``pytest`` configuration, and Python version being used +to run ``pytest``. Note that for assert statements with a manually provided message, i.e. ``assert expr, message``, no assertion introspection takes place and the manually provided message will be rendered in tracebacks. -By default, if the Python version is greater than or equal to 2.6, py.test +By default, if the Python version is greater than or equal to 2.6, ``pytest`` rewrites assert statements in test modules. Rewritten assert statements put -introspection information into the assertion failure message. py.test only +introspection information into the assertion failure message. ``pytest`` only rewrites test modules directly discovered by its test collection process, so asserts in supporting modules which are not themselves test modules will not be rewritten. .. note:: - py.test rewrites test modules on import. It does this by using an import hook - to write a new pyc files. Most of the time this works transparently. However, - if you are messing with import yourself, the import hook may interfere. If - this is the case, simply use ``--assert=reinterp`` or + ``pytest`` rewrites test modules on import. It does this by using an import + hook to write a new pyc files. Most of the time this works transparently. + However, if you are messing with import yourself, the import hook may + interfere. If this is the case, simply use ``--assert=reinterp`` or ``--assert=plain``. Additionally, rewriting will fail silently if it cannot write new pycs, i.e. in a read-only filesystem or a zipfile. If an assert statement has not been rewritten or the Python version is less than -2.6, py.test falls back on assert reinterpretation. In assert reinterpretation, -py.test walks the frame of the function containing the assert statement to -discover sub-expression results of the failing assert statement. You can force -py.test to always use assertion reinterpretation by passing the -``--assert=reinterp`` option. +2.6, ``pytest`` falls back on assert reinterpretation. In assert +reinterpretation, ``pytest`` walks the frame of the function containing the +assert statement to discover sub-expression results of the failing assert +statement. You can force ``pytest`` to always use assertion reinterpretation by +passing the ``--assert=reinterp`` option. Assert reinterpretation has a caveat not present with assert rewriting: If evaluating the assert expression has side effects you may get a warning that the @@ -250,7 +250,7 @@ All assert introspection can be turned off by passing ``--assert=plain``. -For further information, Benjamin Peterson wrote up `Behind the scenes of py.test's new assertion rewriting `_. +For further information, Benjamin Peterson wrote up `Behind the scenes of pytest's new assertion rewriting `_. .. versionadded:: 2.1 Add assert rewriting as an alternate introspection technique. diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/bash-completion.txt --- a/doc/en/bash-completion.txt +++ b/doc/en/bash-completion.txt @@ -4,7 +4,7 @@ Setting up bash completion ========================== -When using bash as your shell, ``py.test`` can use argcomplete +When using bash as your shell, ``pytest`` can use argcomplete (https://argcomplete.readthedocs.org/) for auto-completion. For this ``argcomplete`` needs to be installed **and** enabled. @@ -16,11 +16,11 @@ sudo activate-global-python-argcomplete -For permanent (but not global) ``py.test`` activation, use:: +For permanent (but not global) ``pytest`` activation, use:: register-python-argcomplete py.test >> ~/.bashrc -For one-time activation of argcomplete for ``py.test`` only, use:: +For one-time activation of argcomplete for ``pytest`` only, use:: eval "$(register-python-argcomplete py.test)" diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/capture.txt --- a/doc/en/capture.txt +++ b/doc/en/capture.txt @@ -23,7 +23,7 @@ Setting capturing methods or disabling capturing ------------------------------------------------- -There are two ways in which ``py.test`` can perform capturing: +There are two ways in which ``pytest`` can perform capturing: * file descriptor (FD) level capturing (default): All writes going to the operating system file descriptors 1 and 2 will be captured. @@ -49,7 +49,7 @@ is that you can use print statements for debugging:: # content of test_module.py - + def setup_function(function): print ("setting up %s" % function) @@ -66,16 +66,16 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items - + test_module.py .F - + ================================= FAILURES ================================= ________________________________ test_func2 ________________________________ - + def test_func2(): > assert False E assert False - + test_module.py:9: AssertionError ----------------------------- Captured stdout ------------------------------ setting up @@ -105,7 +105,7 @@ function finishes the original streams will be restored. Using ``capsys`` this way frees your test from having to care about setting/resetting -output streams and also interacts well with py.test's +output streams and also interacts well with pytest's own per-test capturing. If you want to capture on ``fd`` level you can use diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/customize.txt --- a/doc/en/customize.txt +++ b/doc/en/customize.txt @@ -17,7 +17,7 @@ How test configuration is read from configuration INI-files ------------------------------------------------------------- -py.test searches for the first matching ini-style configuration file +``pytest`` searches for the first matching ini-style configuration file in the directories of command line argument and the directories above. It looks for file basenames in this order:: @@ -26,8 +26,8 @@ setup.cfg Searching stops when the first ``[pytest]`` section is found in any of -these files. There is no merging of configuration values from multiple -files. Example:: +these files. There is no merging of configuration values from multiple +files. Example:: py.test path/to/testdir @@ -41,7 +41,7 @@ path/to/setup.cfg ... # up until root of filesystem -If argument is provided to a py.test run, the current working directory +If argument is provided to a ``pytest`` run, the current working directory is used to start the search. .. _`how to change command line options defaults`: @@ -51,7 +51,7 @@ ------------------------------------------------ It can be tedious to type the same series of command line options -every time you use py.test . For example, if you always want to see +every time you use ``pytest``. For example, if you always want to see detailed info on skipped and xfailed tests, as well as have terser "dot" progress output, you can write it into a configuration file:: @@ -60,7 +60,7 @@ [pytest] addopts = -rsxX -q -From now on, running ``py.test`` will add the specified options. +From now on, running ``pytest`` will add the specified options. Builtin configuration file options ---------------------------------------------- @@ -105,7 +105,7 @@ [pytest] norecursedirs = .svn _build tmp* - This would tell py.test to not look into typical subversion or + This would tell ``pytest`` to not look into typical subversion or sphinx-build directories or into any ``tmp`` prefixed directory. .. confval:: python_files @@ -122,7 +122,7 @@ One or more name prefixes determining which test functions and methods are considered as test modules. Note that this - has no effect on methods that live on a ``unittest.TestCase`` + has no effect on methods that live on a ``unittest.TestCase`` derived class. See :ref:`change naming conventions` for examples. diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/develop.txt --- a/doc/en/develop.txt +++ b/doc/en/develop.txt @@ -1,5 +1,5 @@ ================================================= -Feedback and contribute to py.test +Feedback and contribute to pytest ================================================= .. toctree:: diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/example/assertion/failure_demo.py --- a/doc/en/example/assertion/failure_demo.py +++ b/doc/en/example/assertion/failure_demo.py @@ -1,4 +1,4 @@ -from py.test import raises +from pytest import raises import py def otherfunc(a,b): diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/example/markers.txt --- a/doc/en/example/markers.txt +++ b/doc/en/example/markers.txt @@ -30,22 +30,22 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:3: test_send_http PASSED - + =================== 2 tests deselected by "-m 'webtest'" =================== ================== 1 passed, 2 deselected in 0.01 seconds ================== Or the inverse, running all tests except the webtest ones:: - + $ py.test -v -m "not webtest" =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:6: test_something_quick PASSED test_server.py:8: test_another PASSED - + ================= 1 tests deselected by "-m 'not webtest'" ================= ================== 2 passed, 1 deselected in 0.01 seconds ================== @@ -63,9 +63,9 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:3: test_send_http PASSED - + ====================== 2 tests deselected by '-khttp' ====================== ================== 1 passed, 2 deselected in 0.01 seconds ================== @@ -75,10 +75,10 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:6: test_something_quick PASSED test_server.py:8: test_another PASSED - + ================= 1 tests deselected by '-knot send_http' ================== ================== 2 passed, 1 deselected in 0.01 seconds ================== @@ -88,10 +88,10 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:3: test_send_http PASSED test_server.py:6: test_something_quick PASSED - + ================= 1 tests deselected by '-khttp or quick' ================== ================== 2 passed, 1 deselected in 0.01 seconds ================== @@ -124,19 +124,19 @@ $ py.test --markers @pytest.mark.webtest: mark a test as a webtest. - + @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - + @pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html - + @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. - - @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures - + + @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures + @pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible. - + @pytest.mark.trylast: mark a hook implementation function such that the plugin machinery will try to call it last/as late as possible. - + For an example on how to add and work with markers from a plugin, see :ref:`adding a custom marker from a plugin`. @@ -150,8 +150,8 @@ * asking for existing markers via ``py.test --markers`` gives good output * typos in function markers are treated as an error if you use - the ``--strict`` option. Later versions of py.test are probably - going to treat non-registered markers as an error. + the ``--strict`` option. Future versions of ``pytest`` are probably + going to start treating non-registered markers as errors at some point. .. _`scoped-marking`: @@ -268,40 +268,40 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items - + test_someenv.py s - + ======================== 1 skipped in 0.01 seconds ========================= - + and here is one that specifies exactly the environment needed:: $ py.test -E stage1 =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items - + test_someenv.py . - + ========================= 1 passed in 0.01 seconds ========================= The ``--markers`` option always gives you a list of available markers:: $ py.test --markers @pytest.mark.env(name): mark test to run only on named environment - + @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - + @pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html - + @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. - - @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures - + + @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures + @pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible. - + @pytest.mark.trylast: mark a hook implementation function such that the plugin machinery will try to call it last/as late as possible. - - + + Reading markers which were set from multiple places ---------------------------------------------------- @@ -337,7 +337,7 @@ Let's run this without capturing output and see what we get:: - $ py.test -q -s + $ py.test -q -s glob args=('function',) kwargs={'x': 3} glob args=('class',) kwargs={'x': 2} glob args=('module',) kwargs={'x': 1} @@ -352,7 +352,7 @@ Consider you have a test suite which marks tests for particular platforms, namely ``pytest.mark.osx``, ``pytest.mark.win32`` etc. and you also have tests that run on all platforms and have no specific -marker. If you now want to have a way to only run the tests +marker. If you now want to have a way to only run the tests for your particular platform, you could use the following plugin:: # content of conftest.py @@ -397,11 +397,11 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items - + test_plat.py s.s. ========================= short test summary info ========================== SKIP [2] /tmp/doc-exec-63/conftest.py:12: cannot run on platform linux2 - + =================== 2 passed, 2 skipped in 0.01 seconds ==================== Note that if you specify a platform via the marker-command line option like this:: @@ -410,13 +410,13 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items - + test_plat.py . - + =================== 3 tests deselected by "-m 'linux2'" ==================== ================== 1 passed, 3 deselected in 0.01 seconds ================== -then the unmarked-tests will not be run. It is thus a way to restrict the run to the specific tests. +then the unmarked-tests will not be run. It is thus a way to restrict the run to the specific tests. Automatically adding markers based on test names -------------------------------------------------------- @@ -435,7 +435,7 @@ def test_interface_complex(): assert 0 - + def test_event_simple(): assert 0 @@ -446,7 +446,7 @@ ``conftest.py`` plugin:: # content of conftest.py - + import pytest def pytest_collection_modifyitems(items): for item in items: @@ -461,9 +461,9 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items - + test_module.py FF - + ================================= FAILURES ================================= __________________________ test_interface_simple ___________________________ test_module.py:3: in test_interface_simple @@ -482,9 +482,9 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items - + test_module.py FFF - + ================================= FAILURES ================================= __________________________ test_interface_simple ___________________________ test_module.py:3: in test_interface_simple diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/example/multipython.py --- a/doc/en/example/multipython.py +++ b/doc/en/example/multipython.py @@ -2,7 +2,8 @@ module containing a parametrized tests testing cross-python serialization via the pickle module. """ -import py, pytest +import py +import pytest pythonlist = ['python2.4', 'python2.5', 'python2.6', 'python2.7', 'python2.8'] @pytest.fixture(params=pythonlist) @@ -18,7 +19,7 @@ def __init__(self, version, picklefile): self.pythonpath = py.path.local.sysfind(version) if not self.pythonpath: - py.test.skip("%r not found" %(version,)) + pytest.skip("%r not found" %(version,)) self.picklefile = picklefile def dumps(self, obj): dumpfile = self.picklefile.dirpath("dump.py") diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/example/parametrize.txt --- a/doc/en/example/parametrize.txt +++ b/doc/en/example/parametrize.txt @@ -6,7 +6,7 @@ .. currentmodule:: _pytest.python -py.test allows to easily parametrize test functions. +``pytest`` allows to easily parametrize test functions. For basic docs, see :ref:`parametrize-basics`. In the following we provide some examples using @@ -55,13 +55,13 @@ ....F ================================= FAILURES ================================= _____________________________ test_compute[4] ______________________________ - + param1 = 4 - + def test_compute(param1): > assert param1 < 4 E assert 4 < 4 - + test_compute.py:3: AssertionError 1 failed, 4 passed in 0.01 seconds @@ -108,9 +108,9 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items - + test_scenarios.py .... - + ========================= 4 passed in 0.01 seconds ========================= If you just collect tests you'll also nicely see 'advanced' and 'basic' as variants for the test function:: @@ -127,7 +127,7 @@ - + ============================= in 0.01 seconds ============================= Note that we told ``metafunc.parametrize()`` that your scenario values @@ -187,7 +187,7 @@ - + ============================= in 0.00 seconds ============================= And then when we run the test:: @@ -196,15 +196,15 @@ .F ================================= FAILURES ================================= _________________________ test_db_initialized[d2] __________________________ - + db = - + def test_db_initialized(db): # a dummy test if db.__class__.__name__ == "DB2": > pytest.fail("deliberately failing for demo purposes") E Failed: deliberately failing for demo purposes - + test_backends.py:6: Failed 1 failed, 1 passed in 0.01 seconds @@ -252,13 +252,13 @@ F.. ================================= FAILURES ================================= ________________________ TestClass.test_equals[2-1] ________________________ - + self = , a = 1, b = 2 - + def test_equals(self, a, b): > assert a == b E assert 1 == 2 - + test_parametrize.py:18: AssertionError 1 failed, 2 passed in 0.01 seconds @@ -290,7 +290,7 @@ If you want to compare the outcomes of several implementations of a given API, you can write test functions that receive the already imported implementations and get skipped in case the implementation is not importable/available. Let's -say we have a "base" implementation and the other (possibly optimized ones) +say we have a "base" implementation and the other (possibly optimized ones) need to provide similar results:: # content of conftest.py @@ -331,24 +331,24 @@ =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items - + test_module.py .s ========================= short test summary info ========================== SKIP [1] /tmp/doc-exec-65/conftest.py:10: could not import 'opt2' - + =================== 1 passed, 1 skipped in 0.01 seconds ==================== You'll see that we don't have a ``opt2`` module and thus the second test run of our ``test_func1`` was skipped. A few notes: - the fixture functions in the ``conftest.py`` file are "session-scoped" because we - don't need to import more than once + don't need to import more than once - if you have multiple test functions and a skipped import, you will see the ``[1]`` count increasing in the report - you can put :ref:`@pytest.mark.parametrize <@pytest.mark.parametrize>` style - parametrization on the test functions to parametrize input/output + parametrization on the test functions to parametrize input/output values as well. diff -r 5cc8f7cc8c26b8010d7350c7783970f3e7758318 -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 doc/en/example/pythoncollection.txt --- a/doc/en/example/pythoncollection.txt +++ b/doc/en/example/pythoncollection.txt @@ -10,7 +10,7 @@ [pytest] norecursedirs = .svn _build tmp* -This would tell py.test to not recurse into typical subversion or sphinx-build directories or into any ``tmp`` prefixed directory. +This would tell ``pytest`` to not recurse into typical subversion or sphinx-build directories or into any ``tmp`` prefixed directory. .. _`change naming conventions`: @@ -28,7 +28,7 @@ python_classes=Check python_functions=check -This would make py.test look for ``check_`` prefixes in +This would make ``pytest`` look for ``check_`` prefixes in Python filenames, ``Check`` prefixes in classes and ``check`` prefixes in functions and classes. For example, if we have:: @@ -50,11 +50,11 @@ - + ============================= in 0.01 seconds ============================= .. note:: - + the ``python_functions`` and ``python_classes`` has no effect for ``unittest.TestCase`` test discovery because pytest delegates detection of test case methods to unittest code. @@ -62,7 +62,7 @@ Interpreting cmdline arguments as Python packages ----------------------------------------------------- -You can use the ``--pyargs`` option to make py.test try +You can use the ``--pyargs`` option to make ``pytest`` try interpreting arguments as python package names, deriving their file system path and then running the test. For example if you have unittest2 installed you can type:: @@ -96,7 +96,7 @@ - + ============================= in 0.01 seconds ============================= customizing test collection to find all .py files @@ -104,7 +104,7 @@ .. regendoc:wipe -You can easily instruct py.test to discover tests from every python file:: +You can easily instruct ``pytest`` to discover tests from every python file:: # content of pytest.ini @@ -112,8 +112,8 @@ python_files = *.py However, many projects will have a ``setup.py`` which they don't want to be imported. Moreover, there may files only importable by a specific python version. -For such cases you can dynamically define files to be ignored by listing -them in a ``conftest.py`` file:: +For such cases you can dynamically define files to be ignored by listing +them in a ``conftest.py`` file:: # content of conftest.py import sys @@ -136,16 +136,16 @@ # content of setup.py 0/0 # will raise exeption if imported -then a pytest run on python2 will find the one test when run with a python2 +then a pytest run on python2 will find the one test when run with a python2 interpreters and will leave out the setup.py file:: - + $ py.test --collect-only =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items - + ============================= in 0.01 seconds ============================= If you run with a Python3 interpreter the moduled added through the conftest.py file will not be considered for test collection. This diff is so big that we needed to truncate the remainder. https://bitbucket.org/hpk42/pytest/commits/fd38769482f2/ Changeset: fd38769482f2 User: jurko Date: 2014-01-18 12:39:16 Summary: fix comment typos Affected #: 3 files diff -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 -r fd38769482f2636dd24f0284dd6e7fa8cb1bb2b6 _pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -467,9 +467,9 @@ def _getpybinargs(self, scriptname): if not self.request.config.getvalue("notoolsonpath"): - # XXX we rely on script refering to the correct environment + # XXX we rely on script referring to the correct environment # we cannot use "(py.std.sys.executable,script)" - # becaue on windows the script is e.g. a py.test.exe + # because on windows the script is e.g. a py.test.exe return (py.std.sys.executable, _pytest_fullpath,) # noqa else: pytest.skip("cannot run %r with --no-tools-on-path" % scriptname) diff -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 -r fd38769482f2636dd24f0284dd6e7fa8cb1bb2b6 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -485,7 +485,7 @@ fin = getattr(self.obj, 'teardown_module', None) if fin is not None: #XXX: nose compat hack, move to nose plugin - # if it takes a positional arg, its probably a pytest style one + # if it takes a positional arg, it's probably a pytest style one # so we pass the current module object if inspect.getargspec(fin)[0]: finalizer = lambda: fin(self.obj) diff -r 2c04f47decfa134aa6df4a574693655efe2b9eb8 -r fd38769482f2636dd24f0284dd6e7fa8cb1bb2b6 testing/test_config.py --- a/testing/test_config.py +++ b/testing/test_config.py @@ -16,7 +16,7 @@ assert config.inicfg['name'] == 'value' def test_getcfg_empty_path(self, tmpdir): - getcfg([''], ['setup.cfg']) #happens on py.test "" + getcfg([''], ['setup.cfg']) #happens on py.test "" def test_append_parse_args(self, testdir, tmpdir): tmpdir.join("setup.cfg").write(py.code.Source(""" Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Jan 18 14:51:57 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 18 Jan 2014 13:51:57 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140118135157.13226.63248@app01.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/b47176c62f2f/ Changeset: b47176c62f2f User: jurko Date: 2014-01-18 13:11:17 Summary: update README.rst docs - pytest is compatible with Python 2.5 instead of 2.4 Affected #: 1 file diff -r 8afb9592588abefd3ffe49d24811acf18deadfb1 -r b47176c62f2f1e2bc7d76c01e761884941d68fa9 README.rst --- a/README.rst +++ b/README.rst @@ -17,7 +17,7 @@ - multi-paradigm support: you can use ``py.test`` to run test suites based on `unittest `_ (or trial), `nose `_ -- single-source compatibility to Python2.4 all the way up to Python3.3, +- single-source compatibility to Python2.5 all the way up to Python3.3, PyPy-1.9 and Jython-2.5.1. - many `external plugins `_. https://bitbucket.org/hpk42/pytest/commits/f8cba485fb9c/ Changeset: f8cba485fb9c User: hpk42 Date: 2014-01-18 14:51:53 Summary: Merged in jurko/pytest (pull request #100) update README.rst docs - pytest is compatible with Python 2.5 instead of 2.4 Affected #: 1 file diff -r fd38769482f2636dd24f0284dd6e7fa8cb1bb2b6 -r f8cba485fb9ca6680d9ee814d094a523a8c0696d README.rst --- a/README.rst +++ b/README.rst @@ -17,7 +17,7 @@ - multi-paradigm support: you can use ``pytest`` to run test suites based on `unittest `_ (or trial), `nose `_ -- single-source compatibility to Python2.4 all the way up to Python3.3, +- single-source compatibility to Python2.5 all the way up to Python3.3, PyPy-1.9 and Jython-2.5.1. - many `external plugins `_. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Jan 18 14:53:15 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 18 Jan 2014 13:53:15 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: added changelog: fixed docs and code to use "pytest" instead of "py.test" Message-ID: <20140118135315.1316.8201@app18.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/542ae28377f5/ Changeset: 542ae28377f5 User: hpk42 Date: 2014-01-18 14:53:04 Summary: added changelog: fixed docs and code to use "pytest" instead of "py.test" everywhere. Thanks Jurko Gspodnetic for the complete PR. Affected #: 1 file diff -r f8cba485fb9ca6680d9ee814d094a523a8c0696d -r 542ae28377f571912b5f1bb3d4474f5c16b51ca4 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,9 @@ trying to import from collections.abc which causes problems for py27/cx_freeze. Thanks Wolfgang L. for reporting and tracking it down. +- fixed docs and code to use "pytest" instead of "py.test" everywhere. + Thanks Jurko Gspodnetic for the complete PR. + 2.5.1 ----------------------------------- Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Sat Jan 18 15:06:05 2014 From: notifications at travis-ci.org (Travis CI) Date: Sat, 18 Jan 2014 14:06:05 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#76 (master - e4130a0) Message-ID: <52da8a4d80e8_22bd8244149@331b9ccb-aa43-40e4-8d63-ee3f83bce9b1.mail> Build Update for hpk42/pytest ------------------------------------- Build: #76 Status: Still Failing Duration: 11 minutes and 44 seconds Commit: e4130a0 (master) Author: holger krekel Message: added changelog: fixed docs and code to use "pytest" instead of "py.test" everywhere. Thanks Jurko Gspodnetic for the complete PR. View the changeset: https://github.com/hpk42/pytest/compare/482e6bd97639...e4130a0809da View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/17181272 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From issues-reply at bitbucket.org Sat Jan 18 22:01:29 2014 From: issues-reply at bitbucket.org (=?utf-8?q?Daniel_Neuh=C3=A4user?=) Date: Sat, 18 Jan 2014 21:01:29 -0000 Subject: [Pytest-commit] Issue #146: setting PYTHONPATH causes tox to crash (hpk42/tox) Message-ID: <20140118210129.18326.60656@app12.ash-private.bitbucket.org> New issue 146: setting PYTHONPATH causes tox to crash https://bitbucket.org/hpk42/tox/issue/146/setting-pythonpath-causes-tox-to-crash Daniel Neuh?user: When I try to set the PYTHONPATH environment variable, tox fails with this traceback: ``` $ PYTHONPATH=../pypy tox GLOB sdist-make: /Users/DasIch/Development/rply/setup.py Traceback (most recent call last): File "/Users/DasIch/Development/dotfiles/virtualenv/envs/rply/bin/tox", line 9, in load_entry_point('tox==1.6.1', 'console_scripts', 'tox')() File "/Users/DasIch/Development/dotfiles/virtualenv/envs/rply/lib/python2.7/site-packages/tox/_cmdline.py", line 26, in main retcode = Session(config).runcommand() File "/Users/DasIch/Development/dotfiles/virtualenv/envs/rply/lib/python2.7/site-packages/tox/_cmdline.py", line 301, in runcommand return self.subcommand_test() File "/Users/DasIch/Development/dotfiles/virtualenv/envs/rply/lib/python2.7/site-packages/tox/_cmdline.py", line 433, in subcommand_test if self.setupenv(venv): File "/Users/DasIch/Development/dotfiles/virtualenv/envs/rply/lib/python2.7/site-packages/tox/_cmdline.py", line 367, in setupenv commandpath = venv.getcommandpath("python") File "/Users/DasIch/Development/dotfiles/virtualenv/envs/rply/lib/python2.7/site-packages/tox/_venv.py", line 85, in getcommandpath p = py.path.local.sysfind(name, paths=[self.envconfig.envbindir]) TypeError: sysfind() got an unexpected keyword argument 'paths' ``` What I would like tox to do is execute the commands in the testenv with PYTHONPATH as I've set it. From commits-noreply at bitbucket.org Sun Jan 19 09:13:17 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 19 Jan 2014 08:13:17 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix name Message-ID: <20140119081317.30281.89267@app06.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/4f43c3a0f463/ Changeset: 4f43c3a0f463 User: hpk42 Date: 2014-01-19 09:13:06 Summary: fix name Affected #: 1 file diff -r 542ae28377f571912b5f1bb3d4474f5c16b51ca4 -r 4f43c3a0f463e01bc6b5a5cea6d521a9a9d3274c CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -6,7 +6,7 @@ Thanks Wolfgang L. for reporting and tracking it down. - fixed docs and code to use "pytest" instead of "py.test" everywhere. - Thanks Jurko Gspodnetic for the complete PR. + Thanks Jurko Gospodnetic for the complete PR. 2.5.1 ----------------------------------- Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Sun Jan 19 09:24:28 2014 From: notifications at travis-ci.org (Travis CI) Date: Sun, 19 Jan 2014 08:24:28 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#77 (master - fbf09e8) Message-ID: <52db8bbc1d4c0_2a02a41691@8b63f44a-0b6e-4593-a5da-07abf13c2e1a.mail> Build Update for hpk42/pytest ------------------------------------- Build: #77 Status: Still Failing Duration: 10 minutes and 19 seconds Commit: fbf09e8 (master) Author: holger krekel Message: fix name View the changeset: https://github.com/hpk42/pytest/compare/e4130a0809da...fbf09e88dd2e View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/17212521 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Sun Jan 19 17:18:25 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 19 Jan 2014 16:18:25 -0000 Subject: [Pytest-commit] commit/pytest: jurko: fix doc typo Message-ID: <20140119161825.29987.33626@app06.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/49260c1de911/ Changeset: 49260c1de911 User: jurko Date: 2014-01-19 10:26:55 Summary: fix doc typo Affected #: 1 file diff -r 4f43c3a0f463e01bc6b5a5cea6d521a9a9d3274c -r 49260c1de9119070fb8cccd84a4bf218594d30a8 doc/en/plugins.txt --- a/doc/en/plugins.txt +++ b/doc/en/plugins.txt @@ -138,7 +138,7 @@ that ``pytest`` finds your plugin module. Entry points are a feature that is provided by `setuptools`_ or `Distribute`_. pytest looks up the ``pytest11`` entrypoint to discover its -plugins and you can thus make your plugin available by definig +plugins and you can thus make your plugin available by defining it in your setuptools/distribute-based setup-invocation: .. sourcecode:: python Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sun Jan 19 18:55:42 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 19 Jan 2014 17:55:42 -0000 Subject: [Pytest-commit] commit/pytest-pep8: hpk42: clarified in setup.py that license is MIT Message-ID: <20140119175542.25524.15347@app08.ash-private.bitbucket.org> 1 new commit in pytest-pep8: https://bitbucket.org/hpk42/pytest-pep8/commits/e9317b1b8eb9/ Changeset: e9317b1b8eb9 User: hpk42 Date: 2014-01-19 18:55:36 Summary: clarified in setup.py that license is MIT Affected #: 2 files diff -r 0a1ae12443cd8b1ad02c5e9dfc2bba7527568049 -r e9317b1b8eb91e0bd3e46b650d765fff616279d1 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +1.0.6 +-------------- + +- clarified in setup.py that license is MIT + 1.0.5 -------------- diff -r 0a1ae12443cd8b1ad02c5e9dfc2bba7527568049 -r e9317b1b8eb91e0bd3e46b650d765fff616279d1 setup.py --- a/setup.py +++ b/setup.py @@ -5,6 +5,7 @@ name='pytest-pep8', description='pytest plugin to check PEP8 requirements', long_description=open("README.txt").read(), + license="MIT license", version='1.0.5', author='Holger Krekel and Ronny Pfannschmidt', author_email='holger.krekel at gmail.com', Repository URL: https://bitbucket.org/hpk42/pytest-pep8/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Mon Jan 20 04:48:19 2014 From: issues-reply at bitbucket.org (=?utf-8?q?Jurko_Gospodneti=C4=87?=) Date: Mon, 20 Jan 2014 03:48:19 -0000 Subject: [Pytest-commit] Issue #425: --markers output does not include markers from plugins in subdirs (hpk42/pytest) Message-ID: <20140120034819.1815.1696@app10.ash-private.bitbucket.org> New issue 425: --markers output does not include markers from plugins in subdirs https://bitbucket.org/hpk42/pytest/issue/425/markers-output-does-not-include-markers Jurko Gospodneti?: When pytest is called with the '--markers' option, it does not seem to collect marker information from plugins in subdirs on time. They get loaded and used correctly for the actual test run, but --markers output does not include information on them. Pull request #104 includes a prepared unit test reproducing and testing for this behaviour. I noticed this on the suds-jurko package where running the tests using Python 2 shows --markers correctly, while running them using Python 3 (tests get run from a different folder after running py2to3 on the entire source base), locally defined plugin markers are not listed. The plugins themselves still get loaded and used correctly for the actual test run, but that seems to occur only after pytest prepares its --markers output. Hope this helps. Best regards, Jurko Gospodneti? From issues-reply at bitbucket.org Mon Jan 20 12:58:28 2014 From: issues-reply at bitbucket.org (Mikhail Korobov) Date: Mon, 20 Jan 2014 11:58:28 -0000 Subject: [Pytest-commit] Issue #147: tox checks wrong paths when updating setuptools dependencies (hpk42/tox) Message-ID: <20140120115828.14395.33811@app01.ash-private.bitbucket.org> New issue 147: tox checks wrong paths when updating setuptools dependencies https://bitbucket.org/hpk42/tox/issue/147/tox-checks-wrong-paths-when-updating Mikhail Korobov: Hi, Tox stopped worked for me for py3 environment; it seems that during package installation pip "sees" packages installed for system interpreter and refuses to install them: ``` (scraping)kmike ~/svn/django-webtest [master]> tox -e py33 -r -v using tox.ini: /Users/kmike/svn/django-webtest/tox.ini using tox-1.6.1 from /Users/kmike/envs/scraping/lib/python2.7/site-packages/tox/__init__.pyc GLOB sdist-make: /Users/kmike/svn/django-webtest/setup.py /Users/kmike/svn/django-webtest$ /Users/kmike/envs/scraping/bin/python2.7 /Users/kmike/svn/django-webtest/setup.py sdist --formats=zip --dist-dir /Users/kmike/svn/django-webtest/.tox/dist >/Users/kmike/svn/django-webtest/.tox/log/tox-0.log py33 recreate: /Users/kmike/svn/django-webtest/.tox/py33 /Users/kmike/svn/django-webtest/.tox$ /usr/local/bin/python3.3 /Users/kmike/envs/scraping/lib/python2.7/site-packages/virtualenv.py --setuptools --python /usr/local/bin/python3.3 py33 >/Users/kmike/svn/django-webtest/.tox/py33/log/py33-0.log py33 installdeps: WebTest, django /Users/kmike/svn/django-webtest$ /Users/kmike/svn/django-webtest/.tox/py33/bin/pip install --pre WebTest django >/Users/kmike/svn/django-webtest/.tox/py33/log/py33-1.log py33 inst: /Users/kmike/svn/django-webtest/.tox/dist/django-webtest-1.7.6.zip /Users/kmike/svn/django-webtest$ /Users/kmike/svn/django-webtest/.tox/py33/bin/pip install --pre /Users/kmike/svn/django-webtest/.tox/dist/django-webtest-1.7.6.zip >/Users/kmike/svn/django-webtest/.tox/py33/log/py33-2.log py33 runtests: commands[0] | python django_webtest_tests/runtests.py /Users/kmike/svn/django-webtest$ /Users/kmike/svn/django-webtest/.tox/py33/bin/python django_webtest_tests/runtests.py Traceback (most recent call last): File "django_webtest_tests/runtests.py", line 8, in from django.core.management import execute_from_command_line ImportError: No module named 'django' ``` This is the pip log - requirements are not installed because pip/setuptools checks wrong paths for some reason: ``` (scraping)kmike ~/svn/django-webtest [master]> cat /Users/kmike/svn/django-webtest/.tox/py33/log/py33-1.log actionid=py33 msg=getenv cmdargs=[local('/Users/kmike/svn/django-webtest/.tox/py33/bin/pip'), 'install', '--pre', 'WebTest', 'django'] env={'PYTHONIOENCODING': 'utf_8', 'PROJECT_HOME': '/Users/kmike/dev', 'VCPROMPT_FORMAT': '[%b%m%u]', 'TERM_PROGRAM_VERSION': '326', 'TMPDIR': '/var/folders/_5/cbsg50991szfp1r9nwxpx8580000gq/T/', 'LOGNAME': 'kmike', 'USER': 'kmike', 'HOME': '/Users/kmike', 'PATH': '/Users/kmike/svn/django-webtest/.tox/py33/bin:/Users/kmike/envs/scraping/bin:/Users/kmike/.pythonbrew/bin:/Users/kmike/.pythonbrew/bin:/usr/local/bin:/usr/local/share/python:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin', 'PS1': '(scraping)\\[$grey\\]\\u \\[$reset\\]\\w \\[$green\\]$(vcprompt)\\[$reset\\]> ', 'DISPLAY': '/tmp/launch-zsNURS/org.macosforge.xquartz:0', 'TERM_PROGRAM': 'Apple_Terminal', 'LANG': 'en_US.UTF-8', 'TERM': 'xterm-256color', 'SHELL': '/bin/bash', 'SHLVL': '1', 'SECURITYSESSIONID': '186a4', 'TEAMLOCAL_DEBUG': '1', 'SHIFTGIG_DEBUG': '1', 'EDITOR': 'nano', 'PYTHONPATH': '', 'WORKON_HOME': '/Users/kmike/envs', 'TERM_SESSION_ID': '8B065A87-6502-4A5D-AC77-A 10654713D5A', 'CC': 'clang', 'FFLAGS': '-ff2c', 'SSH_AUTH_SOCK': '/tmp/launch-GaV36y/Listeners', 'FAB_COMPLETION_CACHE_TASKS': 'true', 'Apple_PubSub_Socket_Render': '/tmp/launch-P6ElIR/Render', '_': '/Users/kmike/envs/scraping/bin/tox', 'VIRTUALENVWRAPPER_PROJECT_FILENAME': '.project', 'VIRTUAL_ENV': '/Users/kmike/envs/scraping', 'VIRTUALENVWRAPPER_HOOK_DIR': '/Users/kmike/envs', 'CXX': 'clang++', 'OLDPWD': '/Users/kmike/svn/nltk', 'FAB_COMPLETION_CACHED_TASKS_FILENAME': '.fab_tasks~', '__CF_USER_TEXT_ENCODING': '0x1F7:0:0', 'PWD': '/Users/kmike/svn/django-webtest', 'PIP_DOWNLOAD_CACHE': '/Users/kmike/.pip/download', '__CHECKFIX1436934': '1'} Requirement already satisfied (use --upgrade to upgrade): WebTest in /usr/local/lib/python3.3/site-packages Requirement already satisfied (use --upgrade to upgrade): django in /usr/local/lib/python3.3/site-packages Requirement already satisfied (use --upgrade to upgrade): six in /usr/local/lib/python3.3/site-packages (from WebTest) Requirement already satisfied (use --upgrade to upgrade): WebOb>=1.2 in /usr/local/lib/python3.3/site-packages (from WebTest) Requirement already satisfied (use --upgrade to upgrade): waitress>=0.8.5 in /usr/local/lib/python3.3/site-packages (from WebTest) Requirement already satisfied (use --upgrade to upgrade): beautifulsoup4 in /usr/local/lib/python3.3/site-packages (from WebTest) Requirement already satisfied (use --upgrade to upgrade): setuptools in /usr/local/lib/python3.3/site-packages/setuptools-1.3.2-py3.3.egg (from waitress>=0.8.5->WebTest) Cleaning up... ``` This is the contents of pip script: ``` (scraping)kmike ~/svn/django-webtest [master]> cat /Users/kmike/svn/django-webtest/.tox/py33/bin/pip #!/usr/local/bin/python3.3 # -*- coding: utf-8 -*- import re import sys from pip import main if __name__ == '__main__': sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) sys.exit(main()) ``` I'm using tox 1.6.1, pip 1.5 and virtualenv 1.11 From commits-noreply at bitbucket.org Mon Jan 20 13:21:29 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 20 Jan 2014 12:21:29 -0000 Subject: [Pytest-commit] commit/pytest: jurko: fix handling MarkDecorators called with a single positional plus keyword args Message-ID: <20140120122129.13757.55796@app02.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/d836cdb04b0e/ Changeset: d836cdb04b0e User: jurko Date: 2014-01-20 01:27:33 Summary: fix handling MarkDecorators called with a single positional plus keyword args When a MarkDecorator instance is called it does the following: 1. If called with a single class as its only positional argument and no additional keyword arguments, it attaches itself to the class so it gets applied automatically to all test cases found in that class. 2. If called with a single function as its only positional argument and no additional keyword arguments, it attaches a MarkInfo object to the function, containing all the arguments already stored internally in the MarkDecorator. 3. When called in any other case, it performs a 'fake construction' call, i.e. it returns a new MarkDecorator instance with the original MarkDecorator's content updated with the arguments passed to this call. When Python applies a function decorator it always passes the target class/ function to the decorator as its positional argument with no additional positional or keyword arguments. However, when MarkDecorator was deciding whether it was being called to decorate a target function/class (cases 1. & 2. as documented above) or to return an updated MarkDecorator (case 3. as documented above), it only checked that it received a single callable positional argument and did not take into consideration whether additional keyword arguments were being passed in as well. With this change, it is now possible to create a pytest mark storing a function/ class parameter passed as its only positional argument and accompanied by one or more additional keyword arguments. Before, it was only possible to do so if the function/class parameter argument was accompanied by at least one other positional argument. Added a related unit test. Updated MarkDecorator doc-string. Affected #: 2 files diff -r 49260c1de9119070fb8cccd84a4bf218594d30a8 -r d836cdb04b0e20411e96fc70245fe396bb09a506 _pytest/mark.py --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -206,6 +206,24 @@ @mark2 def test_function(): pass + + When a MarkDecorator instance is called it does the following: + 1. If called with a single class as its only positional argument and no + additional keyword arguments, it attaches itself to the class so it + gets applied automatically to all test cases found in that class. + 2. If called with a single function as its only positional argument and + no additional keyword arguments, it attaches a MarkInfo object to the + function, containing all the arguments already stored internally in + the MarkDecorator. + 3. When called in any other case, it performs a 'fake construction' call, + i.e. it returns a new MarkDecorator instance with the original + MarkDecorator's content updated with the arguments passed to this + call. + + Note: The rules above prevent MarkDecorator objects from storing only a + single function or class reference as their positional argument with no + additional keyword or positional arguments. + """ def __init__(self, name, args=None, kwargs=None): self.name = name @@ -224,7 +242,7 @@ def __call__(self, *args, **kwargs): """ if passed a single callable argument: decorate it with mark info. otherwise add *args/**kwargs in-place to mark information. """ - if args: + if args and not kwargs: func = args[0] if len(args) == 1 and (istestfunc(func) or hasattr(func, '__bases__')): diff -r 49260c1de9119070fb8cccd84a4bf218594d30a8 -r d836cdb04b0e20411e96fc70245fe396bb09a506 testing/test_mark.py --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -57,6 +57,17 @@ assert f.world.args[0] == "hello" mark.world("world")(f) + def test_pytest_mark_positional_func_and_keyword(self): + mark = Mark() + def f(): + raise Exception + m = mark.world(f, omega="hello") + def g(): + pass + assert m(g) == g + assert g.world.args[0] is f + assert g.world.kwargs["omega"] == "hello" + def test_pytest_mark_reuse(self): mark = Mark() def f(): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Mon Jan 20 13:22:35 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 20 Jan 2014 12:22:35 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140120122235.10662.32721@app02.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/4b4c7006b925/ Changeset: 4b4c7006b925 Branch: no-p-option User: derdon Date: 2014-01-19 22:05:14 Summary: added docs about the `no:` syntax for the -p option Affected #: 2 files diff -r 49260c1de9119070fb8cccd84a4bf218594d30a8 -r 4b4c7006b925c4f7b4b088caf497a85b9052a59e _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -12,7 +12,9 @@ help="show help message and configuration info") group._addoption('-p', action="append", dest="plugins", default = [], metavar="name", - help="early-load given plugin (multi-allowed).") + help="early-load given plugin (multi-allowed). " + "To avoid loading of plugins, use the `no:` prefix, e.g. " + "`no:doctest`.") group.addoption('--traceconfig', '--trace-config', action="store_true", default=False, help="trace considerations of conftest.py files."), diff -r 49260c1de9119070fb8cccd84a4bf218594d30a8 -r 4b4c7006b925c4f7b4b088caf497a85b9052a59e doc/en/usage.txt --- a/doc/en/usage.txt +++ b/doc/en/usage.txt @@ -153,6 +153,17 @@ Currently only pasting to the http://bpaste.net service is implemented. +Disabling plugins +----------------- + +To disable loading specific plugins at invocation time, use the ``-p`` option +together with the prefix ``no:``. + +Example: to disable loading the plugin ``doctest``, which is responsible for +executing doctest tests from text files, invoke py.test like this:: + + py.test -p no:doctest + .. _`pytest.main-usage`: Calling pytest from Python code https://bitbucket.org/hpk42/pytest/commits/7e50e96912a2/ Changeset: 7e50e96912a2 User: hpk42 Date: 2014-01-20 13:22:31 Summary: Merged in derdon/pytest/no-p-option (pull request #102) added docs about the `no:` syntax for the -p option Affected #: 2 files diff -r d836cdb04b0e20411e96fc70245fe396bb09a506 -r 7e50e96912a21240cc8dcd65a3c1fcf2e0b9cd6c _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -12,7 +12,9 @@ help="show help message and configuration info") group._addoption('-p', action="append", dest="plugins", default = [], metavar="name", - help="early-load given plugin (multi-allowed).") + help="early-load given plugin (multi-allowed). " + "To avoid loading of plugins, use the `no:` prefix, e.g. " + "`no:doctest`.") group.addoption('--traceconfig', '--trace-config', action="store_true", default=False, help="trace considerations of conftest.py files."), diff -r d836cdb04b0e20411e96fc70245fe396bb09a506 -r 7e50e96912a21240cc8dcd65a3c1fcf2e0b9cd6c doc/en/usage.txt --- a/doc/en/usage.txt +++ b/doc/en/usage.txt @@ -153,6 +153,17 @@ Currently only pasting to the http://bpaste.net service is implemented. +Disabling plugins +----------------- + +To disable loading specific plugins at invocation time, use the ``-p`` option +together with the prefix ``no:``. + +Example: to disable loading the plugin ``doctest``, which is responsible for +executing doctest tests from text files, invoke py.test like this:: + + py.test -p no:doctest + .. _`pytest.main-usage`: Calling pytest from Python code Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Mon Jan 20 13:29:03 2014 From: issues-reply at bitbucket.org (holger krekel) Date: Mon, 20 Jan 2014 12:29:03 -0000 Subject: [Pytest-commit] Issue #426: contributor page (hpk42/pytest) Message-ID: <20140120122903.23904.51324@app07.ash-private.bitbucket.org> New issue 426: contributor page https://bitbucket.org/hpk42/pytest/issue/426/contributor-page holger krekel: As @pfctdayelise points out, we don't have a contributor page that says how and where to prepare a pull request. From notifications at travis-ci.org Mon Jan 20 19:49:02 2014 From: notifications at travis-ci.org (Travis CI) Date: Mon, 20 Jan 2014 18:49:02 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#78 (master - b51ed06) Message-ID: <52dd6f9dce4c8_21129be4360944@5931ddb3-a9fd-49f3-b256-e151f9c3f5df.mail> Build Update for hpk42/pytest ------------------------------------- Build: #78 Status: Still Failing Duration: 12 minutes and 44 seconds Commit: b51ed06 (master) Author: holger krekel Message: Merged in derdon/pytest/no-p-option (pull request #102) added docs about the `no:` syntax for the -p option View the changeset: https://github.com/hpk42/pytest/compare/fbf09e88dd2e...b51ed06fdebc View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/17292625 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From issues-reply at bitbucket.org Tue Jan 21 06:52:29 2014 From: issues-reply at bitbucket.org (Richard Jones) Date: Tue, 21 Jan 2014 05:52:29 -0000 Subject: [Pytest-commit] Issue #148: __PYVENV_LAUNCHER__ causing issues on OS X with Python 3.3 (hpk42/tox) Message-ID: <20140121055229.4274.88029@app13.ash-private.bitbucket.org> New issue 148: __PYVENV_LAUNCHER__ causing issues on OS X with Python 3.3 https://bitbucket.org/hpk42/tox/issue/148/__pyvenv_launcher__-causing-issues-on-os-x Richard Jones: If the environment variable __PYVENV_LAUNCHER__ is set when tox is launched then the pip subprocesses that tox fires off to install dependencies get confused and install everything into the virtualenv that tox comes from, rather than the test envs. The "fix" is to add __PYVENV_LAUNCHER__ to the list of environment variables deleted from the environment in the _pcall method (along with VIRTUALENV_PYTHON and PYTHONDONTWRITEBYTECODE). Sorry I can't provide a better report than this but I'm not sure what __PYVENV_LAUNCHER__ does - only that it causes trouble sometimes and is the specific cause of the problem in this case. I've attached the output/logs of trying to run tox with flake8, with what I hope is a reasonable explanation of what's going on. It's kinda verbose, sorry, but it does show the failure and then success after I make the edit above. From issues-reply at bitbucket.org Tue Jan 21 09:25:29 2014 From: issues-reply at bitbucket.org (=?utf-8?q?Jurko_Gospodneti=C4=87?=) Date: Tue, 21 Jan 2014 08:25:29 -0000 Subject: [Pytest-commit] Issue #427: Option to have pytest rewrite assertions in additional non-test modules (hpk42/pytest) Message-ID: <20140121082529.23956.23319@app02.ash-private.bitbucket.org> New issue 427: Option to have pytest rewrite assertions in additional non-test modules https://bitbucket.org/hpk42/pytest/issue/427/option-to-have-pytest-rewrite-assertions Jurko Gospodneti?: Sometimes, when refactoring a project's test code, it becomes useful to extract some useful project specific testing functions into a separate testing utility module. A function in that module may then perform an assertion while actual test functions just call that utility function as needed. Problem in this case is that such assertions are ignored when running the tests using the '-O' command-line option. However, assertions used directly inside test modules are not, since pytest's assertion rewriting preserves them. This could be resolved by allowing a project to list extra modules pytest's assertion rewriting should be applied to. A new configuration option seems like a natural way to allow this. Some alternative solution ideas: 1. It is possible to refactor the project code so that the utility function just returns a True/False boolean indicator and then have the test function assert that the function returned True, but having the function perform the actual assertion often provides better error reports in case of test failure. For example, if you have a utility function comparing two XML structures, it seems much better if the test fails and reports that node X on one side and node X on the other side have different content, then if it just says 'the two XML documents do not match'. 2. Utility functions could raise some sort of a project specific exception instead of an assertion failure - a bit smelly, would not directly provide a clean test failure explanation error message but would allow the user to drop into the debugger at the location where the exception was raised. Best regards, Jurko Gospodneti? From issues-reply at bitbucket.org Wed Jan 22 10:10:26 2014 From: issues-reply at bitbucket.org (Andreas Pelme) Date: Wed, 22 Jan 2014 09:10:26 -0000 Subject: [Pytest-commit] Issue #428: test_package_without__init__py failure (hpk42/pytest) Message-ID: <20140122091026.17574.60261@app08.ash-private.bitbucket.org> New issue 428: test_package_without__init__py failure https://bitbucket.org/hpk42/pytest/issue/428/test_package_without__init__py-failure Andreas Pelme: This test fails when I run the test suite: ``` #!text [pytest] ~/code/pytest $ py.test -vvv -k test_package_without__init__py ================================ test session starts ================================ platform darwin -- Python 2.7.5 -- pytest-2.5.2.dev1 -- /Users/andreas/.virtualenvs/pytest/bin/python collected 1033 items testing/test_assertrewrite.py:414: TestRewriteOnImport.test_package_without__init__py FAILED ===================================== FAILURES ====================================== ________________ TestRewriteOnImport.test_package_without__init__py _________________ self = testdir = def test_package_without__init__py(self, testdir): pkg = testdir.mkdir('a_package_without_init_py') mod = pkg.join('module.py').ensure() testdir.makepyfile("import a_package_without_init_py.module") > assert testdir.runpytest().ret == 0 E assert 1 == 0 E + where 1 = <_pytest.pytester.RunResult instance at 0x1098d9a28>.ret E + where <_pytest.pytester.RunResult instance at 0x1098d9a28> = >() E + where > = .runpytest /Users/andreas/code/pytest/testing/test_assertrewrite.py:418: AssertionError ---------------------------------- Captured stdout ---------------------------------- running ['/Users/andreas/.virtualenvs/pytest/bin/python', '/Users/andreas/code/pytest/pytest.py', '--basetemp=/private/var/folders/2w/bh7b385124b2wy0vkkcv0s9w0000gn/T/pytest-109/testdir/test_package_without__init__py0/runpytest-0'] curdir= /private/var/folders/2w/bh7b385124b2wy0vkkcv0s9w0000gn/T/pytest-109/testdir/test_package_without__init__py0 ============================= test session starts ============================== platform darwin -- Python 2.7.5 -- pytest-2.5.2.dev1 collected 0 items / 1 errors ==================================== ERRORS ==================================== ______________ ERROR collecting test_package_without__init__py.py ______________ test_package_without__init__py.py:1: in > import a_package_without_init_py.module E ImportError: No module named a_package_without_init_py.module =========================== 1 error in 0.01 seconds ============================ ============ 1032 tests deselected by '-ktest_package_without__init__py' ============ ===================== 1 failed, 1032 deselected in 0.96 seconds ===================== ``` From commits-noreply at bitbucket.org Wed Jan 22 10:24:29 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 09:24:29 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix issue425: mention at end of "py.test -h" that --markers Message-ID: <20140122092429.12052.16345@app04.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/b1c00e260afe/ Changeset: b1c00e260afe User: hpk42 Date: 2014-01-22 10:24:22 Summary: fix issue425: mention at end of "py.test -h" that --markers and --fixtures work according to specified test path (or current dir) Affected #: 2 files diff -r 7e50e96912a21240cc8dcd65a3c1fcf2e0b9cd6c -r b1c00e260afe4a51cc6a94109e1a2a75d304e4b1 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,9 @@ - fixed docs and code to use "pytest" instead of "py.test" everywhere. Thanks Jurko Gospodnetic for the complete PR. +- fix issue425: mention at end of "py.test -h" that --markers + and --fixtures work according to specified test path (or current dir) + 2.5.1 ----------------------------------- diff -r 7e50e96912a21240cc8dcd65a3c1fcf2e0b9cd6c -r b1c00e260afe4a51cc6a94109e1a2a75d304e4b1 _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -84,6 +84,8 @@ #tw.sep("=") tw.line("to see available markers type: py.test --markers") tw.line("to see available fixtures type: py.test --fixtures") + tw.line("(shown according to specified file_or_dir or current dir " + "if not specified)") return tw.line("conftest.py options:") Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 11:17:33 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 10:17:33 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fixed circular imports by reverting a few py.test -> pytest substitions. Message-ID: <20140122101733.13766.30972@app02.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/c22101120b20/ Changeset: c22101120b20 User: hpk42 Date: 2014-01-22 11:17:25 Summary: fixed circular imports by reverting a few py.test -> pytest substitions. Affected #: 3 files diff -r b1c00e260afe4a51cc6a94109e1a2a75d304e4b1 -r c22101120b20464ee112485a11891d6fa98fbe01 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -5,12 +5,13 @@ trying to import from collections.abc which causes problems for py27/cx_freeze. Thanks Wolfgang L. for reporting and tracking it down. -- fixed docs and code to use "pytest" instead of "py.test" everywhere. - Thanks Jurko Gospodnetic for the complete PR. +- fixed docs and code to use "pytest" instead of "py.test" almost everywhere. + Thanks Jurko Gospodnetic for the complete PR. - fix issue425: mention at end of "py.test -h" that --markers and --fixtures work according to specified test path (or current dir) + 2.5.1 ----------------------------------- diff -r b1c00e260afe4a51cc6a94109e1a2a75d304e4b1 -r c22101120b20464ee112485a11891d6fa98fbe01 _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -1,7 +1,7 @@ """ command line options, ini-file and conftest.py processing. """ import py -import pytest +# DON't import pytest here because it causes import cycle troubles import sys, os from _pytest import hookspec # the extension point definitions from _pytest.core import PluginManager @@ -817,7 +817,8 @@ raise KeyError(name) return val except KeyError: - pytest.skip("no %r value found" %(name,)) + import pytest + py.test.skip("no %r value found" %(name,)) def exists(path, ignore=EnvironmentError): try: diff -r b1c00e260afe4a51cc6a94109e1a2a75d304e4b1 -r c22101120b20464ee112485a11891d6fa98fbe01 _pytest/core.py --- a/_pytest/core.py +++ b/_pytest/core.py @@ -4,7 +4,7 @@ import sys import inspect import py -import pytest +# don't import pytest to avoid circular imports assert py.__version__.split(".")[:2] >= ['1', '4'], ("installation problem: " "%s is too old, remove or upgrade 'py'" % (py.__version__)) @@ -137,7 +137,7 @@ def skipifmissing(self, name): if not self.hasplugin(name): - pytest.skip("plugin %r is missing" % name) + py.test.skip("plugin %r is missing" % name) def hasplugin(self, name): return bool(self.getplugin(name)) @@ -221,9 +221,9 @@ raise except: e = py.std.sys.exc_info()[1] - if not hasattr(pytest, 'skip'): + if not hasattr(py.test, 'skip'): raise - elif not isinstance(e, pytest.skip.Exception): + elif not isinstance(e, py.test.skip.Exception): raise self._hints.append("skipped plugin %r: %s" %((modname, e.msg))) else: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 11:27:28 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 10:27:28 -0000 Subject: [Pytest-commit] commit/pytest: flub: Include py version in the terminal output Message-ID: <20140122102728.29834.9437@app03.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/2c70f1b3ee81/ Changeset: 2c70f1b3ee81 User: flub Date: 2014-01-22 11:27:15 Summary: Include py version in the terminal output This can help to reproduce bugs when looking at the output pasted into bug reports. Affected #: 2 files diff -r c22101120b20464ee112485a11891d6fa98fbe01 -r 2c70f1b3ee817c7945a7ebd3a671a777f97f8c91 _pytest/terminal.py --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -259,7 +259,7 @@ if hasattr(sys, 'pypy_version_info'): verinfo = ".".join(map(str, sys.pypy_version_info[:3])) msg += "[pypy-%s-%s]" % (verinfo, sys.pypy_version_info[3]) - msg += " -- pytest-%s" % (pytest.__version__) + msg += " -- py-%s -- pytest-%s" % (py.__version__, pytest.__version__) if self.verbosity > 0 or self.config.option.debug or \ getattr(self.config.option, 'pastebin', None): msg += " -- " + str(sys.executable) diff -r c22101120b20464ee112485a11891d6fa98fbe01 -r 2c70f1b3ee817c7945a7ebd3a671a777f97f8c91 testing/test_terminal.py --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -408,8 +408,9 @@ verinfo = ".".join(map(str, py.std.sys.version_info[:3])) result.stdout.fnmatch_lines([ "*===== test session starts ====*", - "platform %s -- Python %s*" % ( - py.std.sys.platform, verinfo), # , py.std.sys.executable), + "platform %s -- Python %s* -- py-%s -- pytest-%s" % ( + py.std.sys.platform, verinfo, + py.__version__, pytest.__version__), "*test_header_trailer_info.py .", "=* 1 passed in *.[0-9][0-9] seconds *=", ]) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 11:46:08 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 10:46:08 -0000 Subject: [Pytest-commit] commit/py: hpk42: bump version to 1.4.20 Message-ID: <20140122104608.11454.22713@app02.ash-private.bitbucket.org> 1 new commit in py: https://bitbucket.org/hpk42/py/commits/509aef38de37/ Changeset: 509aef38de37 User: hpk42 Date: 2014-01-22 11:46:02 Summary: bump version to 1.4.20 Affected #: 3 files diff -r f25cbde63642edd32c8cbbc9eae842c1cb3486ec -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -UNRELEASED +1.4.20 ================================================== - ignore unicode decode errors in xmlescape. Thanks Anatoly Bubenkoff. diff -r f25cbde63642edd32c8cbbc9eae842c1cb3486ec -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2013 """ -__version__ = '1.4.20.dev1' +__version__ = '1.4.20' from py import _apipkg diff -r f25cbde63642edd32c8cbbc9eae842c1cb3486ec -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 setup.py --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ name='py', description='library with cross-python path, ini-parsing, io, code, log facilities', long_description = open('README.txt').read(), - version='1.4.20.dev1', + version='1.4.20', url='http://pylib.readthedocs.org/', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Wed Jan 22 12:05:32 2014 From: notifications at travis-ci.org (Travis CI) Date: Wed, 22 Jan 2014 11:05:32 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#80 (master - 04f91db) Message-ID: <52dfa5fbec540_22a121252ce@2989fa5b-c362-4c07-8437-995223c89bab.mail> Build Update for hpk42/pytest ------------------------------------- Build: #80 Status: Still Failing Duration: 13 minutes and 32 seconds Commit: 04f91db (master) Author: Floris Bruynooghe Message: Include py version in the terminal output This can help to reproduce bugs when looking at the output pasted into bug reports. View the changeset: https://github.com/hpk42/pytest/compare/b51ed06fdebc...04f91db1ce9a View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/17401904 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Wed Jan 22 13:54:39 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 12:54:39 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: remove superflous line Message-ID: <20140122125439.4356.83753@app08.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/2cd4476cf643/ Changeset: 2cd4476cf643 User: hpk42 Date: 2014-01-22 13:54:25 Summary: remove superflous line Affected #: 1 file diff -r 2c70f1b3ee817c7945a7ebd3a671a777f97f8c91 -r 2cd4476cf6433894acfc0448dc68132368143c3c _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -817,7 +817,6 @@ raise KeyError(name) return val except KeyError: - import pytest py.test.skip("no %r value found" %(name,)) def exists(path, ignore=EnvironmentError): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 14:31:39 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 13:31:39 -0000 Subject: [Pytest-commit] commit/pytest: jurko: add test: '--markers' listing info from plugins in current folder Message-ID: <20140122133139.14846.29589@app02.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/e9d4d4eb38c1/ Changeset: e9d4d4eb38c1 User: jurko Date: 2014-01-22 14:16:39 Summary: add test: '--markers' listing info from plugins in current folder When pytest is called with the '--markers' option, it should collect marker information from the current folder, and they should get loaded and used correctly before the '--markers' output is constructed. Affected #: 1 file diff -r 2cd4476cf6433894acfc0448dc68132368143c3c -r e9d4d4eb38c195bc3913baca20c1b17e4f93c43a testing/test_mark.py --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -115,6 +115,28 @@ "*a1some*another marker", ]) +def test_markers_option_with_plugin_in_current_dir(testdir): + testdir.makeconftest('pytest_plugins = "flip_flop"') + testdir.makepyfile(flip_flop="""\ + def pytest_configure(config): + config.addinivalue_line("markers", "flip:flop") + + def pytest_generate_tests(metafunc): + try: + mark = metafunc.function.flipper + except AttributeError: + return + metafunc.parametrize("x", (10, 20))""") + testdir.makepyfile("""\ + import pytest + @pytest.mark.flipper + def test_example(x): + assert x""") + + result = testdir.runpytest("--markers") + result.stdout.fnmatch_lines(["*flip*flop*"]) + + def test_mark_on_pseudo_function(testdir): testdir.makepyfile(""" import pytest Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 14:46:25 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 13:46:25 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140122134625.15879.7535@app08.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/77925d29cf0b/ Changeset: 77925d29cf0b Branch: py2_pkg_skip User: pelme Date: 2014-01-22 14:32:22 Summary: fixed issue428: Skip test for packages without __init__.py on Python 2 Affected #: 1 file diff -r 7e50e96912a21240cc8dcd65a3c1fcf2e0b9cd6c -r 77925d29cf0bd3d7e87255e3c69739e28dba621f testing/test_assertrewrite.py --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -411,6 +411,13 @@ testdir.tmpdir.join("test_newlines.py").write(b, "wb") assert testdir.runpytest().ret == 0 + @pytest.mark.skipif(sys.version_info[0] == 2, + reason='packages without __init__.py not supported on python 2') + def test_package_without__init__py(self, testdir): + pkg = testdir.mkdir('a_package_without_init_py') + mod = pkg.join('module.py').ensure() + testdir.makepyfile("import a_package_without_init_py.module") + assert testdir.runpytest().ret == 0 class TestAssertionRewriteHookDetails(object): def test_loader_is_package_false_for_module(self, testdir): https://bitbucket.org/hpk42/pytest/commits/97806c888bae/ Changeset: 97806c888bae User: hpk42 Date: 2014-01-22 14:46:22 Summary: Merged in pelme/pytest/py2_pkg_skip (pull request #107) fixed issue428: Skip test for packages without __init__.py on Python 2 Affected #: 1 file diff -r e9d4d4eb38c195bc3913baca20c1b17e4f93c43a -r 97806c888bae964d7cc0549eb575b12bffce89f7 testing/test_assertrewrite.py --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -411,6 +411,13 @@ testdir.tmpdir.join("test_newlines.py").write(b, "wb") assert testdir.runpytest().ret == 0 + @pytest.mark.skipif(sys.version_info[0] == 2, + reason='packages without __init__.py not supported on python 2') + def test_package_without__init__py(self, testdir): + pkg = testdir.mkdir('a_package_without_init_py') + mod = pkg.join('module.py').ensure() + testdir.makepyfile("import a_package_without_init_py.module") + assert testdir.runpytest().ret == 0 class TestAssertionRewriteHookDetails(object): def test_loader_is_package_false_for_module(self, testdir): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 17:37:52 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 16:37:52 -0000 Subject: [Pytest-commit] commit/py: hpk42: fix unicode related issues -- but this changing two things currently. Message-ID: <20140122163752.13620.72923@app13.ash-private.bitbucket.org> 1 new commit in py: https://bitbucket.org/hpk42/py/commits/a890a2fd1e8b/ Changeset: a890a2fd1e8b User: hpk42 Date: 2014-01-22 17:37:22 Summary: fix unicode related issues -- but this changing two things currently. Affected #: 7 files diff -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,12 @@ - ignore unicode decode errors in xmlescape. Thanks Anatoly Bubenkoff. +- on python2 modify traceback.format_exception_only to match python3 + behaviour, namely trying to print unicode for Exception instances + +- use a safer way for serializing exception reports (helps to fix + pytest issue413) + Changes between 1.4.18 and 1.4.19 ================================================== diff -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2013 """ -__version__ = '1.4.20' +__version__ = '1.4.20.dev2' from py import _apipkg diff -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -6,6 +6,35 @@ reprlib = py.builtin._tryimport('repr', 'reprlib') +if sys.version_info[0] >= 3: + from traceback import format_exception_only +else: + import traceback + def format_exception_only(etype, evalue): + """ return list of unicode strings if possible (otherwise bytestrings) + """ + # we patch traceback._some_str to try return unicode to have nicer + # printing of exceptions with unicode attributes in tracebacks. + # Alternative to monkeypatching we would need to copy + # python-2.7's format_exception_only and its induced functions + # -- which seems like overkill. + def somestr(value): + try: + return unicode(value) + except Exception: + try: + return str(value) + except Exception: + pass + return '' % type(value).__name__ + + old = traceback._some_str + traceback._some_str = somestr + try: + return traceback.format_exception_only(etype, evalue) + finally: + traceback._some_str = old + class Code(object): """ wrapper around Python code objects """ def __init__(self, rawcode): @@ -374,7 +403,7 @@ if isinstance(value, AssertionError) and hasattr(value, 'msg'): return ['AssertionError: ' + value.msg] else: - return py.std.traceback.format_exception_only(etype, value) + return format_exception_only(etype, value) def errisinstance(self, exc): """ return True if the exception is an instance of exc """ @@ -594,22 +623,16 @@ return s def __unicode__(self): - l = [] - tw = py.io.TerminalWriter(l.append) + # FYI this is called from pytest-xdist's serialization of exception + # information. + io = py.io.TextIO() + tw = py.io.TerminalWriter(file=io) self.toterminal(tw) - l = map(unicode_or_repr, l) - return "".join(l).strip() + return io.getvalue().strip() def __repr__(self): return "<%s instance at %0x>" %(self.__class__, id(self)) -def unicode_or_repr(obj): - try: - return py.builtin._totext(obj) - except KeyboardInterrupt: - raise - except Exception: - return "" % py.io.saferepr(obj) class ReprExceptionInfo(TerminalRepr): def __init__(self, reprtraceback, reprcrash): diff -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 setup.py --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ name='py', description='library with cross-python path, ini-parsing, io, code, log facilities', long_description = open('README.txt').read(), - version='1.4.20', + version='1.4.20.dev2', url='http://pylib.readthedocs.org/', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 testing/code/test_code.py --- a/testing/code/test_code.py +++ b/testing/code/test_code.py @@ -89,23 +89,6 @@ if sys.version_info[0] < 3: u = unicode(excinfo) -def test_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') - else: - s = eval("unicode_or_repr(b'\\f6\\xc4\\x85')") - assert 'print-error' in s - assert 'c4' in s - class A: - def __repr__(self): - raise ValueError() - s = unicode_or_repr(A()) - assert 'print-error' in s - assert 'ValueError' in s - - def test_code_getargs(): def f1(x): pass diff -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 testing/code/test_excinfo.py --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -727,6 +727,14 @@ assert isinstance(repr, ReprExceptionInfo) assert repr.reprtraceback.style == style + def test_reprexcinfo_unicode(self): + from py._code.code import TerminalRepr + class MyRepr(TerminalRepr): + def toterminal(self, tw): + tw.line(py.builtin._totext("?", "utf-8")) + x = py.builtin._totext(MyRepr()) + assert x == py.builtin._totext("?", "utf-8") + def test_toterminal_long(self, importasmod): mod = importasmod(""" def g(x): diff -r 509aef38de37c70f12d1b706f8b69b0e712bbfe2 -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 testing/io_/test_saferepr.py --- a/testing/io_/test_saferepr.py +++ b/testing/io_/test_saferepr.py @@ -76,18 +76,3 @@ if sys.version_info[0] < 3: u = unicode(excinfo) -def test_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') - else: - s = eval("unicode_or_repr(b'\\f6\\xc4\\x85')") - assert 'print-error' in s - assert 'c4' in s - class A: - def __repr__(self): - raise ValueError() - s = unicode_or_repr(A()) - assert 'print-error' in s - assert 'ValueError' in s Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 17:49:39 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 16:49:39 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix issue413: exceptions with unicode attributes are now printed Message-ID: <20140122164939.8319.90141@app08.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/0761626cf9a5/ Changeset: 0761626cf9a5 User: hpk42 Date: 2014-01-22 17:48:56 Summary: fix issue413: exceptions with unicode attributes are now printed correctly also on python2 and with pytest-xdist runs. (the fix requires py-1.4.20) Affected #: 2 files diff -r 97806c888bae964d7cc0549eb575b12bffce89f7 -r 0761626cf9a54ad7b68e802808d77448c9919bc6 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,9 @@ - fix issue425: mention at end of "py.test -h" that --markers and --fixtures work according to specified test path (or current dir) +- fix issue413: exceptions with unicode attributes are now printed + correctly also on python2 and with pytest-xdist runs. (the fix + requires py-1.4.20) 2.5.1 ----------------------------------- diff -r 97806c888bae964d7cc0549eb575b12bffce89f7 -r 0761626cf9a54ad7b68e802808d77448c9919bc6 setup.py --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ long_description = open("README.rst").read() def main(): - install_requires = ["py>=1.4.19"] + install_requires = ["py>=1.4.20.dev2"] if sys.version_info < (2,7): install_requires.append("argparse") if sys.platform == "win32": Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Wed Jan 22 18:05:16 2014 From: issues-reply at bitbucket.org (Ronan Lamy) Date: Wed, 22 Jan 2014 17:05:16 -0000 Subject: [Pytest-commit] Issue #429: Assert interpretation chokes on mojibake (Python 2.7) (hpk42/pytest) Message-ID: <20140122170516.5456.98802@app10.ash-private.bitbucket.org> New issue 429: Assert interpretation chokes on mojibake (Python 2.7) https://bitbucket.org/hpk42/pytest/issue/429/assert-interpretation-chokes-on-mojibake Ronan Lamy: Self-explanatory, I hope. AIUI, the line that fails is doing u''.join([, ]) which can only end in tears. ``` #! $ py.test test_mojibake.py --pdb ======================================================================================================== test session starts ======================================================================================================== platform linux2 -- Python 2.7.4 -- pytest-2.5.1 plugins: cov collected 1 items test_mojibake.py F >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> def test_test(): > assert 'e' == '\xc3\xa9' test_mojibake.py:2: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ops = ('==',), results = (False,), expls = ('%(py1)s == %(py4)s',), each_obj = ('e', '\xc3\xa9') def _call_reprcompare(ops, results, expls, each_obj): for i, res, expl in zip(range(len(ops)), results, expls): try: done = not res except Exception: done = True if done: break if util._reprcompare is not None: > custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) ../../.virtualenvs/hippy/local/lib/python2.7/site-packages/_pytest/assertion/rewrite.py:343: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ op = '==', left = 'e', right = '\xc3\xa9' def callbinrepr(op, left, right): hook_result = item.ihook.pytest_assertrepr_compare( config=item.config, op=op, left=left, right=right) for new_expl in hook_result: if new_expl: # Don't include pageloads of data unless we are very # verbose (-vv) > if (len(py.builtin._totext('').join(new_expl[1:])) > 80*8 and item.config.option.verbose < 2): E UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2: ordinal not in range(128) ../../.virtualenvs/hippy/local/lib/python2.7/site-packages/_pytest/assertion/__init__.py:83: UnicodeDecodeError >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > /home/ronan/.virtualenvs/hippy/local/lib/python2.7/site-packages/_pytest/assertion/__init__.py(83)callbinrepr() -> if (len(py.builtin._totext('').join(new_expl[1:])) > 80*8 (Pdb) p new_expl [u"'e' == '\\xc3\\xa9'", '- e', '+ \xc3\xa9'] ``` From commits-noreply at bitbucket.org Wed Jan 22 18:09:22 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 17:09:22 -0000 Subject: [Pytest-commit] commit/py: hpk42: rather than monkeypatching use a copy of the involved Message-ID: <20140122170922.3383.40200@app18.ash-private.bitbucket.org> 1 new commit in py: https://bitbucket.org/hpk42/py/commits/13d9af95547e/ Changeset: 13d9af95547e User: hpk42 Date: 2014-01-22 18:08:50 Summary: rather than monkeypatching use a copy of the involved code for traceback.format_exception_only and simplify invocation places. Affected #: 2 files diff -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 -r 13d9af95547ea14b2e33e2994ff96e182da225c4 py/_code/_py2traceback.py --- /dev/null +++ b/py/_code/_py2traceback.py @@ -0,0 +1,79 @@ +# copied from python-2.7.3's traceback.py +# CHANGES: +# - some_str is replaced, trying to create unicode strings +# +import types + +def format_exception_only(etype, value): + """Format the exception part of a traceback. + + The arguments are the exception type and value such as given by + sys.last_type and sys.last_value. The return value is a list of + strings, each ending in a newline. + + Normally, the list contains a single string; however, for + SyntaxError exceptions, it contains several lines that (when + printed) display detailed information about where the syntax + error occurred. + + The message indicating which exception occurred is always the last + string in the list. + + """ + + # An instance should not have a meaningful value parameter, but + # sometimes does, particularly for string exceptions, such as + # >>> raise string1, string2 # deprecated + # + # Clear these out first because issubtype(string1, SyntaxError) + # would throw another exception and mask the original problem. + if (isinstance(etype, BaseException) or + isinstance(etype, types.InstanceType) or + etype is None or type(etype) is str): + return [_format_final_exc_line(etype, value)] + + stype = etype.__name__ + + if not issubclass(etype, SyntaxError): + return [_format_final_exc_line(stype, value)] + + # It was a syntax error; show exactly where the problem was found. + lines = [] + try: + msg, (filename, lineno, offset, badline) = value.args + except Exception: + pass + else: + filename = filename or "" + lines.append(' File "%s", line %d\n' % (filename, lineno)) + if badline is not None: + lines.append(' %s\n' % badline.strip()) + if offset is not None: + caretspace = badline.rstrip('\n')[:offset].lstrip() + # non-space whitespace (likes tabs) must be kept for alignment + caretspace = ((c.isspace() and c or ' ') for c in caretspace) + # only three spaces to account for offset1 == pos 0 + lines.append(' %s^\n' % ''.join(caretspace)) + value = msg + + lines.append(_format_final_exc_line(stype, value)) + return lines + +def _format_final_exc_line(etype, value): + """Return a list of a single line -- normal case for format_exception_only""" + valuestr = _some_str(value) + if value is None or not valuestr: + line = "%s\n" % etype + else: + line = "%s: %s\n" % (etype, valuestr) + return line + +def _some_str(value): + try: + return unicode(value) + except Exception: + try: + return str(value) + except Exception: + pass + return '' % type(value).__name__ diff -r a890a2fd1e8b3004cec17fce5c363241ca1161f7 -r 13d9af95547ea14b2e33e2994ff96e182da225c4 py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -9,31 +9,7 @@ if sys.version_info[0] >= 3: from traceback import format_exception_only else: - import traceback - def format_exception_only(etype, evalue): - """ return list of unicode strings if possible (otherwise bytestrings) - """ - # we patch traceback._some_str to try return unicode to have nicer - # printing of exceptions with unicode attributes in tracebacks. - # Alternative to monkeypatching we would need to copy - # python-2.7's format_exception_only and its induced functions - # -- which seems like overkill. - def somestr(value): - try: - return unicode(value) - except Exception: - try: - return str(value) - except Exception: - pass - return '' % type(value).__name__ - - old = traceback._some_str - traceback._some_str = somestr - try: - return traceback.format_exception_only(etype, evalue) - finally: - traceback._some_str = old + from py._code._py2traceback import format_exception_only class Code(object): """ wrapper around Python code objects """ @@ -386,7 +362,7 @@ the exception representation is returned (so 'AssertionError: ' is removed from the beginning) """ - lines = self._format_exception_only(self.type, self.value) + lines = format_exception_only(self.type, self.value) text = ''.join(lines) text = text.rstrip() if tryshort: @@ -394,17 +370,6 @@ text = text[len(self._striptext):] return text - def _format_exception_only(self, etype, value): - """Format the exception part of a traceback - - Since traceback.format_exception_only() destroys unicode on - python 2 we handle plain AsssertionErrors separately here. - """ - if isinstance(value, AssertionError) and hasattr(value, 'msg'): - return ['AssertionError: ' + value.msg] - else: - return format_exception_only(etype, value) - def errisinstance(self, exc): """ return True if the exception is an instance of exc """ return isinstance(self.value, exc) Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 18:12:59 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 17:12:59 -0000 Subject: [Pytest-commit] commit/pytest: RonnyPfannschmidt: xfailing test for captire encoding issues with binary stdio Message-ID: <20140122171259.13580.82392@app02.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/ed53fc170092/ Changeset: ed53fc170092 User: RonnyPfannschmidt Date: 2014-01-22 18:07:54 Summary: xfailing test for captire encoding issues with binary stdio Affected #: 1 file diff -r 0761626cf9a54ad7b68e802808d77448c9919bc6 -r ed53fc170092dd91959751cf85b63c6ffe0fc3b7 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -493,3 +493,26 @@ result = testdir.runpytest("-vs") assert result.ret == 0 assert 'hello19' in result.stdout.str() + + at pytest.mark.xfail(sys.version_info >= (3, 0), reason='encoding issues') +def test_capture_binary_output(testdir): + testdir.makepyfile(""" + import pytest + + def test_a(): + import sys + import subprocess + subprocess.call([sys.executable, __file__]) + + @pytest.mark.skip + def test_foo(): + import os;os.write(1, b'\xc3') + + if __name__ == '__main__': + test_foo() + """) + result = testdir.runpytest('--assert=plain') + result.stdout.fnmatch_lines([ + '*2 passed*', + ]) + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Wed Jan 22 18:01:16 2014 From: notifications at travis-ci.org (Travis CI) Date: Wed, 22 Jan 2014 17:01:16 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#81 (master - 9ed6ac1) Message-ID: <52dff95a99908_23ceb764245a6@a61fcca5-78ea-4d9f-b72f-35aa4285875d.mail> Build Update for hpk42/pytest ------------------------------------- Build: #81 Status: Still Failing Duration: 54 seconds Commit: 9ed6ac1 (master) Author: holger krekel Message: fix issue413: exceptions with unicode attributes are now printed correctly also on python2 and with pytest-xdist runs. (the fix requires py-1.4.20) View the changeset: https://github.com/hpk42/pytest/compare/04f91db1ce9a...9ed6ac11b971 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/17421313 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Wed Jan 22 22:00:36 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 21:00:36 -0000 Subject: [Pytest-commit] commit/pytest: 11 new changesets Message-ID: <20140122210036.19882.59204@app04.ash-private.bitbucket.org> 11 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/38769d230633/ Changeset: 38769d230633 User: RonnyPfannschmidt Date: 2014-01-22 19:04:38 Summary: initial code import for capture transfer Affected #: 2 files diff -r ed53fc170092dd91959751cf85b63c6ffe0fc3b7 -r 38769d230633e6e2b1e6ce02743b961e4f704af2 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -1,17 +1,24 @@ -""" per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments. """ - -import pytest, py +""" + per-test stdout/stderr capturing mechanisms, + ``capsys`` and ``capfd`` function arguments. +""" import sys import os +import py +import pytest + def pytest_addoption(parser): group = parser.getgroup("general") - group._addoption('--capture', action="store", default=None, + group._addoption( + '--capture', action="store", default=None, metavar="method", 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.") + @pytest.mark.tryfirst def pytest_load_initial_conftests(early_config, parser, args, __multicall__): ns = parser.parse_known_args(args) @@ -246,3 +253,374 @@ def close(self): self._finalize() +import os +import sys +import py +import tempfile + +try: + from io import StringIO +except ImportError: + from StringIO import StringIO + +if sys.version_info < (3,0): + class TextIO(StringIO): + def write(self, data): + if not isinstance(data, unicode): + data = unicode(data, getattr(self, '_encoding', 'UTF-8'), 'replace') + StringIO.write(self, data) +else: + TextIO = StringIO + +try: + from io import BytesIO +except ImportError: + class BytesIO(StringIO): + def write(self, data): + if isinstance(data, unicode): + raise TypeError("not a byte value: %r" %(data,)) + StringIO.write(self, data) + +patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} + +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 + specified a tempfile.Tempfile() will be opened + in text mode. + """ + self.targetfd = targetfd + if tmpfile is None and targetfd != 0: + f = tempfile.TemporaryFile('wb+') + tmpfile = dupfile(f, encoding="UTF-8") + f.close() + self.tmpfile = tmpfile + self._savefd = os.dup(self.targetfd) + if patchsys: + self._oldsys = getattr(sys, patchsysdict[targetfd]) + if now: + self.start() + + def start(self): + try: + os.fstat(self._savefd) + except OSError: + raise ValueError("saved filedescriptor not valid, " + "did you call start() twice?") + if self.targetfd == 0 and not self.tmpfile: + fd = os.open(devnullpath, os.O_RDONLY) + os.dup2(fd, 0) + os.close(fd) + if hasattr(self, '_oldsys'): + setattr(sys, patchsysdict[self.targetfd], DontReadFromInput()) + else: + os.dup2(self.tmpfile.fileno(), self.targetfd) + if hasattr(self, '_oldsys'): + setattr(sys, patchsysdict[self.targetfd], self.tmpfile) + + def done(self): + """ unpatch and clean up, returns the self.tmpfile (file object) + """ + 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 + + def writeorg(self, data): + """ write a string to the original file descriptor + """ + tempfp = tempfile.TemporaryFile() + try: + os.dup2(self._savefd, tempfp.fileno()) + tempfp.write(data) + finally: + tempfp.close() + + +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 + 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() + mode = mode or f.mode + except AttributeError: + if raising: + raise + return f + newfd = os.dup(fd) + if sys.version_info >= (3,0): + if encoding is not None: + mode = mode.replace("b", "") + buffering = True + return os.fdopen(newfd, mode, buffering, encoding, closefd=True) + else: + f = os.fdopen(newfd, mode, buffering) + if encoding is not None: + return EncodedFile(f, encoding) + return f + +class EncodedFile(object): + def __init__(self, _stream, encoding): + self._stream = _stream + self.encoding = encoding + + def write(self, obj): + if isinstance(obj, unicode): + obj = obj.encode(self.encoding) + elif isinstance(obj, str): + pass + else: + obj = str(obj) + self._stream.write(obj) + + def writelines(self, linelist): + data = ''.join(linelist) + self.write(data) + + def __getattr__(self, name): + return getattr(self._stream, name) + +class Capture(object): + def call(cls, func, *args, **kwargs): + """ return a (res, out, err) tuple where + out and err represent the output/error output + during function execution. + call the given function with args/kwargs + and capture output/error during its execution. + """ + so = cls() + try: + res = func(*args, **kwargs) + finally: + out, err = so.reset() + return res, out, err + call = classmethod(call) + + def reset(self): + """ reset sys.stdout/stderr and return captured output as strings. """ + if hasattr(self, '_reset'): + raise ValueError("was already reset") + self._reset = True + outfile, errfile = self.done(save=False) + out, err = "", "" + if outfile and not outfile.closed: + out = outfile.read() + outfile.close() + if errfile and errfile != outfile and not errfile.closed: + err = errfile.read() + errfile.close() + return out, err + + def suspend(self): + """ return current snapshot captures, memorize tempfiles. """ + outerr = self.readouterr() + outfile, errfile = self.done() + return outerr + + +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. + """ + def __init__(self, out=True, err=True, mixed=False, + in_=True, patchsys=True, now=True): + self._options = { + "out": out, + "err": err, + "mixed": mixed, + "in_": in_, + "patchsys": patchsys, + "now": now, + } + self._save() + if now: + self.startall() + + def _save(self): + in_ = self._options['in_'] + out = self._options['out'] + err = self._options['err'] + mixed = self._options['mixed'] + patchsys = self._options['patchsys'] + if in_: + try: + self.in_ = FDCapture(0, tmpfile=None, now=False, + patchsys=patchsys) + except OSError: + pass + if out: + tmpfile = None + if hasattr(out, 'write'): + tmpfile = out + try: + self.out = FDCapture(1, tmpfile=tmpfile, + now=False, patchsys=patchsys) + self._options['out'] = self.out.tmpfile + except OSError: + pass + if err: + if out and mixed: + 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._options['err'] = self.err.tmpfile + except OSError: + pass + + def startall(self): + if hasattr(self, 'in_'): + self.in_.start() + if hasattr(self, 'out'): + self.out.start() + if hasattr(self, 'err'): + self.err.start() + + def resume(self): + """ resume capturing with original temp files. """ + self.startall() + + def done(self, save=True): + """ return (outfile, errfile) and stop capturing. """ + outfile = errfile = None + if hasattr(self, 'out') and not self.out.tmpfile.closed: + outfile = self.out.done() + if hasattr(self, 'err') and not self.err.tmpfile.closed: + errfile = self.err.done() + if hasattr(self, 'in_'): + tmpfile = self.in_.done() + if save: + self._save() + return outfile, errfile + + def readouterr(self): + """ return snapshot value of stdout/stderr capturings. """ + if hasattr(self, "out"): + out = self._readsnapshot(self.out.tmpfile) + else: + out = "" + if hasattr(self, "err"): + err = self._readsnapshot(self.err.tmpfile) + else: + err = "" + return [out, err] + + def _readsnapshot(self, f): + f.seek(0) + res = f.read() + enc = getattr(f, "encoding", None) + if enc: + res = py.builtin._totext(res, enc, "replace") + f.truncate(0) + f.seek(0) + return res + + +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). + """ + def __init__(self, out=True, err=True, in_=True, mixed=False, now=True): + self._oldout = sys.stdout + self._olderr = sys.stderr + self._oldin = sys.stdin + if out and not hasattr(out, 'file'): + out = TextIO() + self.out = out + if err: + if mixed: + err = out + elif not hasattr(err, 'write'): + err = TextIO() + self.err = err + self.in_ = in_ + if now: + self.startall() + + def startall(self): + if self.out: + sys.stdout = self.out + if self.err: + sys.stderr = self.err + if self.in_: + sys.stdin = self.in_ = DontReadFromInput() + + def done(self, save=True): + """ return (outfile, errfile) and stop capturing. """ + outfile = errfile = None + if self.out and not self.out.closed: + 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 + errfile.seek(0) + if self.in_: + sys.stdin = self._oldin + return outfile, errfile + + def resume(self): + """ resume capturing with original temp files. """ + self.startall() + + def readouterr(self): + """ return snapshot value of stdout/stderr capturings. """ + out = err = "" + if self.out: + out = self.out.getvalue() + self.out.truncate(0) + self.out.seek(0) + if self.err: + err = self.err.getvalue() + self.err.truncate(0) + self.err.seek(0) + return out, err + +class DontReadFromInput: + """Temporary stub class. Ideally when stdin is accessed, the + capturing should be turned off, with possibly all data captured + so far sent to the screen. This should be configurable, though, + because in automated test runs it is better to crash than + hang indefinitely. + """ + def read(self, *args): + raise IOError("reading from stdin while output is captured") + readline = read + readlines = read + __iter__ = read + + def fileno(self): + raise ValueError("redirected Stdin is pseudofile, has no fileno()") + def isatty(self): + return False + def close(self): + pass + +try: + devnullpath = os.devnull +except AttributeError: + if os.name == 'nt': + devnullpath = 'NUL' + else: + devnullpath = '/dev/null' diff -r ed53fc170092dd91959751cf85b63c6ffe0fc3b7 -r 38769d230633e6e2b1e6ce02743b961e4f704af2 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,4 +1,9 @@ -import pytest, py, os, sys +from __future__ import with_statement +import os +import sys +import py +import pytest + from _pytest.capture import CaptureManager needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')") @@ -496,7 +501,7 @@ @pytest.mark.xfail(sys.version_info >= (3, 0), reason='encoding issues') def test_capture_binary_output(testdir): - testdir.makepyfile(""" + testdir.makepyfile(r""" import pytest def test_a(): @@ -516,3 +521,503 @@ '*2 passed*', ]) + +import os, sys +import py + +needsdup = py.test.mark.skipif("not hasattr(os, 'dup')") + +from py.builtin import print_ + +if sys.version_info >= (3,0): + def tobytes(obj): + if isinstance(obj, str): + obj = obj.encode('UTF-8') + assert isinstance(obj, bytes) + return obj + def totext(obj): + if isinstance(obj, bytes): + obj = str(obj, 'UTF-8') + assert isinstance(obj, str) + return obj +else: + def tobytes(obj): + if isinstance(obj, unicode): + obj = obj.encode('UTF-8') + assert isinstance(obj, str) + return obj + def totext(obj): + if isinstance(obj, str): + obj = unicode(obj, 'UTF-8') + assert isinstance(obj, unicode) + return obj + +def oswritebytes(fd, obj): + os.write(fd, tobytes(obj)) + +class TestTextIO: + def test_text(self): + f = py.io.TextIO() + f.write("hello") + s = f.getvalue() + assert s == "hello" + f.close() + + def test_unicode_and_str_mixture(self): + f = py.io.TextIO() + if sys.version_info >= (3,0): + f.write("\u00f6") + py.test.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))") + else: + f.write(unicode("\u00f6", 'UTF-8')) + f.write("hello") # bytes + s = f.getvalue() + f.close() + assert isinstance(s, unicode) + +def test_bytes_io(): + f = py.io.BytesIO() + f.write(tobytes("hello")) + py.test.raises(TypeError, "f.write(totext('hello'))") + s = f.getvalue() + assert s == tobytes("hello") + +def test_dontreadfrominput(): + from py._io.capture import DontReadFromInput + f = DontReadFromInput() + 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(ValueError, f.fileno) + f.close() # just for completeness + +def pytest_funcarg__tmpfile(request): + testdir = request.getfuncargvalue("testdir") + f = testdir.makepyfile("").open('wb+') + request.addfinalizer(f.close) + return f + + at needsdup +def test_dupfile(tmpfile): + flist = [] + 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 + print_(i, end="", file=nf) + flist.append(nf) + for i in range(5): + f = flist[i] + f.close() + tmpfile.seek(0) + s = tmpfile.read() + assert "01234" in repr(s) + tmpfile.close() + +def test_dupfile_no_mode(): + """ + dupfile should trap an AttributeError and return f if no mode is supplied. + """ + class SomeFileWrapper(object): + "An object with a fileno method but no mode attribute" + def fileno(self): + return 1 + tmpfile = SomeFileWrapper() + assert py.io.dupfile(tmpfile) is tmpfile + with py.test.raises(AttributeError): + py.io.dupfile(tmpfile, raising=True) + +def lsof_check(func): + pid = os.getpid() + try: + out = py.process.cmdexec("lsof -p %d" % pid) + except py.process.cmdexec.Error: + py.test.skip("could not run 'lsof'") + func() + out2 = py.process.cmdexec("lsof -p %d" % pid) + len1 = len([x for x in out.split("\n") if "REG" in x]) + len2 = len([x for x in out2.split("\n") if "REG" in x]) + assert len2 < len1 + 3, out2 + +class TestFDCapture: + pytestmark = needsdup + + def test_not_now(self, tmpfile): + fd = tmpfile.fileno() + cap = py.io.FDCapture(fd, now=False) + data = tobytes("hello") + os.write(fd, data) + f = cap.done() + s = f.read() + assert not s + cap = py.io.FDCapture(fd, now=False) + cap.start() + os.write(fd, data) + f = cap.done() + s = f.read() + assert s == "hello" + + def test_simple(self, tmpfile): + fd = tmpfile.fileno() + cap = py.io.FDCapture(fd) + data = tobytes("hello") + os.write(fd, data) + f = cap.done() + s = f.read() + assert s == "hello" + f.close() + + def test_simple_many(self, tmpfile): + for i in range(10): + self.test_simple(tmpfile) + + def test_simple_many_check_open_files(self, tmpfile): + lsof_check(lambda: self.test_simple_many(tmpfile)) + + def test_simple_fail_second_start(self, tmpfile): + fd = tmpfile.fileno() + cap = py.io.FDCapture(fd) + f = cap.done() + py.test.raises(ValueError, cap.start) + f.close() + + 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): + tmpfile.write(tobytes("3")) + tmpfile.seek(0) + cap = py.io.FDCapture(0, tmpfile=tmpfile) + # check with os.read() directly instead of raw_input(), because + # sys.stdin itself may be redirected (as py.test now does by default) + x = os.read(0, 100).strip() + f = cap.done() + assert x == tobytes("3") + + def test_writeorg(self, tmpfile): + data1, data2 = tobytes("foo"), tobytes("bar") + try: + cap = py.io.FDCapture(tmpfile.fileno()) + tmpfile.write(data1) + cap.writeorg(data2) + finally: + tmpfile.close() + f = cap.done() + scap = f.read() + assert scap == totext(data1) + stmp = open(tmpfile.name, 'rb').read() + assert stmp == data2 + + +class TestStdCapture: + def getcapture(self, **kw): + return py.io.StdCapture(**kw) + + def test_capturing_done_simple(self): + cap = self.getcapture() + sys.stdout.write("hello") + sys.stderr.write("world") + outfile, errfile = cap.done() + s = outfile.read() + assert s == "hello" + s = errfile.read() + assert s == "world" + + def test_capturing_reset_simple(self): + cap = self.getcapture() + print("hello world") + sys.stderr.write("hello error\n") + out, err = cap.reset() + assert out == "hello world\n" + assert err == "hello error\n" + + def test_capturing_readouterr(self): + cap = self.getcapture() + try: + print ("hello world") + sys.stderr.write("hello error\n") + out, err = cap.readouterr() + assert out == "hello world\n" + assert err == "hello error\n" + sys.stderr.write("error2") + finally: + out, err = cap.reset() + assert err == "error2" + + def test_capturing_readouterr_unicode(self): + cap = self.getcapture() + print ("hx\xc4\x85\xc4\x87") + out, err = cap.readouterr() + assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8") + + @py.test.mark.skipif('sys.version_info >= (3,)', + reason='text output different for bytes on python3') + def test_capturing_readouterr_decode_error_handling(self): + cap = self.getcapture() + # triggered a internal error in pytest + print('\xa6') + out, err = cap.readouterr() + assert out == py.builtin._totext('\ufffd\n', 'unicode-escape') + + def test_capturing_mixed(self): + cap = self.getcapture(mixed=True) + sys.stdout.write("hello ") + sys.stderr.write("world") + sys.stdout.write(".") + out, err = cap.reset() + assert out.strip() == "hello world." + assert not err + + def test_reset_twice_error(self): + cap = self.getcapture() + print ("hello") + out, err = cap.reset() + py.test.raises(ValueError, cap.reset) + assert out == "hello\n" + assert not err + + def test_capturing_modify_sysouterr_in_between(self): + 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() + 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 + + def test_capturing_error_recursive(self): + cap1 = self.getcapture() + print ("cap1") + cap2 = self.getcapture() + print ("cap2") + out2, err2 = cap2.reset() + out1, err1 = cap1.reset() + assert out1 == "cap1\n" + assert out2 == "cap2\n" + + 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 + + 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 + + def test_stdin_restored(self): + old = sys.stdin + cap = self.getcapture(in_=True) + newstdin = sys.stdin + out, err = cap.reset() + assert newstdin != sys.stdin + assert sys.stdin is old + + def test_stdin_nulled_by_default(self): + print ("XXX this test may well hang instead of crashing") + print ("XXX which indicates an error in the underlying capturing") + print ("XXX mechanisms") + cap = self.getcapture() + py.test.raises(IOError, "sys.stdin.read()") + out, err = cap.reset() + + def test_suspend_resume(self): + cap = self.getcapture(out=True, err=False, in_=False) + try: + print ("hello") + sys.stderr.write("error\n") + out, err = cap.suspend() + assert out == "hello\n" + assert not err + print ("in between") + sys.stderr.write("in between\n") + cap.resume() + print ("after") + sys.stderr.write("error_after\n") + finally: + out, err = cap.reset() + assert out == "after\n" + assert not err + +class TestStdCaptureNotNow(TestStdCapture): + def getcapture(self, **kw): + kw['now'] = False + cap = py.io.StdCapture(**kw) + cap.startall() + return cap + +class TestStdCaptureFD(TestStdCapture): + pytestmark = needsdup + + def getcapture(self, **kw): + return py.io.StdCaptureFD(**kw) + + def test_intermingling(self): + cap = self.getcapture() + oswritebytes(1, "1") + sys.stdout.write(str(2)) + sys.stdout.flush() + oswritebytes(1, "3") + oswritebytes(2, "a") + sys.stderr.write("b") + sys.stderr.flush() + oswritebytes(2, "c") + out, err = cap.reset() + assert out == "123" + assert err == "abc" + + 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") + + def test_many(self, capfd): + def f(): + for i in range(10): + cap = py.io.StdCaptureFD() + cap.reset() + lsof_check(f) + +class TestStdCaptureFDNotNow(TestStdCaptureFD): + pytestmark = needsdup + + def getcapture(self, **kw): + kw['now'] = False + cap = py.io.StdCaptureFD(**kw) + cap.startall() + return cap + + at needsdup +def test_stdcapture_fd_tmpfile(tmpfile): + capfd = py.io.StdCaptureFD(out=tmpfile) + os.write(1, "hello".encode("ascii")) + os.write(2, "world".encode("ascii")) + outf, errf = capfd.done() + assert outf == tmpfile + +class TestStdCaptureFDinvalidFD: + pytestmark = needsdup + def test_stdcapture_fd_invalid_fd(self, testdir): + testdir.makepyfile(""" + import py, os + def test_stdout(): + os.close(1) + cap = py.io.StdCaptureFD(out=True, err=False, in_=False) + cap.done() + def test_stderr(): + os.close(2) + cap = py.io.StdCaptureFD(out=False, err=True, in_=False) + cap.done() + def test_stdin(): + os.close(0) + cap = py.io.StdCaptureFD(out=False, err=False, in_=True) + cap.done() + """) + result = testdir.runpytest("--capture=fd") + assert result.ret == 0 + assert result.parseoutcomes()['passed'] == 3 + +def test_capture_not_started_but_reset(): + capsys = py.io.StdCapture(now=False) + capsys.done() + capsys.done() + capsys.reset() + + at needsdup +def test_capture_no_sys(): + capsys = py.io.StdCapture() + try: + cap = py.io.StdCaptureFD(patchsys=False) + sys.stdout.write("hello") + sys.stderr.write("world") + oswritebytes(1, "1") + oswritebytes(2, "2") + out, err = cap.reset() + assert out == "1" + assert err == "2" + finally: + capsys.reset() + + at needsdup +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) + finally: + capfd.reset() + assert res == 42 + assert out.startswith("3") + assert err.startswith("4") + + at needsdup + at py.test.mark.parametrize('use', [True, False]) +def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): + if not use: + tmpfile = True + cap = py.io.StdCaptureFD(out=False, err=tmpfile, now=False) + cap.startall() + capfile = cap.err.tmpfile + cap.suspend() + cap.resume() + capfile2 = cap.err.tmpfile + assert capfile2 == capfile + + at py.test.mark.parametrize('method', ['StdCapture', 'StdCaptureFD']) +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 + p = testdir.makepyfile(""" + import sys, os + import py, logging + cap = py.io.%s(out=False, in_=False) + + logging.warn("hello1") + outerr = cap.suspend() + print ("suspend, captured %%s" %%(outerr,)) + logging.warn("hello2") + + cap.resume() + logging.warn("hello3") + + outerr = cap.suspend() + print ("suspend2, captured %%s" %% (outerr,)) + """ % (method,)) + result = testdir.runpython(p) + result.stdout.fnmatch_lines([ + "suspend, captured*hello1*", + "suspend2, captured*hello2*WARNING:root:hello3*", + ]) + assert "atexit" not in result.stderr.str() https://bitbucket.org/hpk42/pytest/commits/980746ed70fb/ Changeset: 980746ed70fb User: RonnyPfannschmidt Date: 2014-01-22 19:32:23 Summary: rewrite all testing uses of py.io to _pytest.capture Affected #: 1 file diff -r 38769d230633e6e2b1e6ce02743b961e4f704af2 -r 980746ed70fb68109632d338905c4f2a5f3469ba testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -4,10 +4,12 @@ import py import pytest +from _pytest import capture from _pytest.capture import CaptureManager needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')") + class TestCaptureManager: def test_getmethod_default_no_fd(self, testdir, monkeypatch): config = testdir.parseconfig(testdir.tmpdir) @@ -39,7 +41,7 @@ @needsosdup @pytest.mark.parametrize("method", ['no', 'fd', 'sys']) def test_capturing_basic_api(self, method): - capouter = py.io.StdCaptureFD() + capouter = capture.StdCaptureFD() old = sys.stdout, sys.stderr, sys.stdin try: capman = CaptureManager() @@ -63,7 +65,7 @@ @needsosdup def test_juggle_capturings(self, testdir): - capouter = py.io.StdCaptureFD() + capouter = capture.StdCaptureFD() try: #config = testdir.parseconfig(testdir.tmpdir) capman = CaptureManager() @@ -85,10 +87,11 @@ finally: capouter.reset() + @pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") @pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_unicode(testdir, method): - if sys.version_info >= (3,0): + if sys.version_info >= (3, 0): obj = "'b\u00f6y'" else: obj = "u'\u00f6y'" @@ -105,6 +108,7 @@ "*1 passed*" ]) + @pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_bytes_in_utf8_encoding(testdir, method): testdir.makepyfile(""" @@ -116,6 +120,7 @@ "*1 passed*" ]) + def test_collect_capturing(testdir): p = testdir.makepyfile(""" print ("collect %s failure" % 13) @@ -127,6 +132,7 @@ "*collect 13 failure*", ]) + class TestPerTestCapturing: def test_capture_and_fixtures(self, testdir): p = testdir.makepyfile(""" @@ -174,7 +180,6 @@ "in teardown*", ]) - def test_no_carry_over(self, testdir): p = testdir.makepyfile(""" def test_func1(): @@ -188,7 +193,6 @@ assert "in func1" not in s assert "in func2" in s - def test_teardown_capturing(self, testdir): p = testdir.makepyfile(""" def setup_function(function): @@ -249,13 +253,14 @@ "2", ]) + class TestLoggingInteraction: def test_logging_stream_ownership(self, testdir): p = testdir.makepyfile(""" def test_logging(): import logging import pytest - stream = py.io.TextIO() + stream = capture.TextIO() logging.basicConfig(stream=stream) stream.close() # to free memory/release resources """) @@ -325,7 +330,8 @@ logging.warn("hello432") assert 0 """) - result = testdir.runpytest(p, "--traceconfig", + result = testdir.runpytest( + p, "--traceconfig", "-p", "no:capturelog") assert result.ret != 0 result.stdout.fnmatch_lines([ @@ -466,6 +472,7 @@ "*1 error*" ]) + def test_fdfuncarg_skips_on_no_osdup(testdir): testdir.makepyfile(""" import os @@ -479,6 +486,7 @@ "*1 skipped*" ]) + def test_capture_conftest_runtest_setup(testdir): testdir.makeconftest(""" def pytest_runtest_setup(): @@ -489,6 +497,7 @@ assert result.ret == 0 assert 'hello19' not in result.stdout.str() + def test_capture_early_option_parsing(testdir): testdir.makeconftest(""" def pytest_runtest_setup(): @@ -499,6 +508,7 @@ assert result.ret == 0 assert 'hello19' in result.stdout.str() + @pytest.mark.xfail(sys.version_info >= (3, 0), reason='encoding issues') def test_capture_binary_output(testdir): testdir.makepyfile(r""" @@ -520,21 +530,20 @@ result.stdout.fnmatch_lines([ '*2 passed*', ]) - -import os, sys -import py -needsdup = py.test.mark.skipif("not hasattr(os, 'dup')") +needsdup = pytest.mark.skipif("not hasattr(os, 'dup')") from py.builtin import print_ -if sys.version_info >= (3,0): + +if sys.version_info >= (3, 0): def tobytes(obj): if isinstance(obj, str): obj = obj.encode('UTF-8') assert isinstance(obj, bytes) return obj + def totext(obj): if isinstance(obj, bytes): obj = str(obj, 'UTF-8') @@ -546,51 +555,57 @@ obj = obj.encode('UTF-8') assert isinstance(obj, str) return obj + def totext(obj): if isinstance(obj, str): obj = unicode(obj, 'UTF-8') assert isinstance(obj, unicode) return obj + def oswritebytes(fd, obj): os.write(fd, tobytes(obj)) + class TestTextIO: def test_text(self): - f = py.io.TextIO() + f = capture.TextIO() f.write("hello") s = f.getvalue() assert s == "hello" f.close() def test_unicode_and_str_mixture(self): - f = py.io.TextIO() - if sys.version_info >= (3,0): + f = capture.TextIO() + if sys.version_info >= (3, 0): f.write("\u00f6") - py.test.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))") + pytest.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) + def test_bytes_io(): - f = py.io.BytesIO() + f = capture.BytesIO() f.write(tobytes("hello")) - py.test.raises(TypeError, "f.write(totext('hello'))") + pytest.raises(TypeError, "f.write(totext('hello'))") s = f.getvalue() assert s == tobytes("hello") + def test_dontreadfrominput(): - from py._io.capture import DontReadFromInput + from _pytest.capture import DontReadFromInput f = DontReadFromInput() 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(ValueError, f.fileno) - f.close() # just for completeness + pytest.raises(IOError, f.read) + pytest.raises(IOError, f.readlines) + pytest.raises(IOError, iter, f) + pytest.raises(ValueError, f.fileno) + f.close() # just for completeness + def pytest_funcarg__tmpfile(request): testdir = request.getfuncargvalue("testdir") @@ -598,11 +613,12 @@ request.addfinalizer(f.close) return f + @needsdup def test_dupfile(tmpfile): flist = [] for i in range(5): - nf = py.io.dupfile(tmpfile, encoding="utf-8") + nf = capture.dupfile(tmpfile, encoding="utf-8") assert nf != tmpfile assert nf.fileno() != tmpfile.fileno() assert nf not in flist @@ -616,6 +632,7 @@ assert "01234" in repr(s) tmpfile.close() + def test_dupfile_no_mode(): """ dupfile should trap an AttributeError and return f if no mode is supplied. @@ -625,34 +642,36 @@ def fileno(self): return 1 tmpfile = SomeFileWrapper() - assert py.io.dupfile(tmpfile) is tmpfile - with py.test.raises(AttributeError): - py.io.dupfile(tmpfile, raising=True) + assert capture.dupfile(tmpfile) is tmpfile + with pytest.raises(AttributeError): + capture.dupfile(tmpfile, raising=True) + def lsof_check(func): pid = os.getpid() try: out = py.process.cmdexec("lsof -p %d" % pid) except py.process.cmdexec.Error: - py.test.skip("could not run 'lsof'") + pytest.skip("could not run 'lsof'") func() out2 = py.process.cmdexec("lsof -p %d" % pid) len1 = len([x for x in out.split("\n") if "REG" in x]) len2 = len([x for x in out2.split("\n") if "REG" in x]) assert len2 < len1 + 3, out2 + class TestFDCapture: pytestmark = needsdup def test_not_now(self, tmpfile): fd = tmpfile.fileno() - cap = py.io.FDCapture(fd, now=False) + cap = capture.FDCapture(fd, now=False) data = tobytes("hello") os.write(fd, data) f = cap.done() s = f.read() assert not s - cap = py.io.FDCapture(fd, now=False) + cap = capture.FDCapture(fd, now=False) cap.start() os.write(fd, data) f = cap.done() @@ -661,7 +680,7 @@ def test_simple(self, tmpfile): fd = tmpfile.fileno() - cap = py.io.FDCapture(fd) + cap = capture.FDCapture(fd) data = tobytes("hello") os.write(fd, data) f = cap.done() @@ -678,13 +697,13 @@ def test_simple_fail_second_start(self, tmpfile): fd = tmpfile.fileno() - cap = py.io.FDCapture(fd) + cap = capture.FDCapture(fd) f = cap.done() - py.test.raises(ValueError, cap.start) + pytest.raises(ValueError, cap.start) f.close() def test_stderr(self): - cap = py.io.FDCapture(2, patchsys=True) + cap = capture.FDCapture(2, patchsys=True) print_("hello", file=sys.stderr) f = cap.done() s = f.read() @@ -693,17 +712,17 @@ def test_stdin(self, tmpfile): tmpfile.write(tobytes("3")) tmpfile.seek(0) - cap = py.io.FDCapture(0, tmpfile=tmpfile) + cap = capture.FDCapture(0, tmpfile=tmpfile) # check with os.read() directly instead of raw_input(), because - # sys.stdin itself may be redirected (as py.test now does by default) + # sys.stdin itself may be redirected (as pytest now does by default) x = os.read(0, 100).strip() - f = cap.done() + cap.done() assert x == tobytes("3") def test_writeorg(self, tmpfile): data1, data2 = tobytes("foo"), tobytes("bar") try: - cap = py.io.FDCapture(tmpfile.fileno()) + cap = capture.FDCapture(tmpfile.fileno()) tmpfile.write(data1) cap.writeorg(data2) finally: @@ -717,7 +736,7 @@ class TestStdCapture: def getcapture(self, **kw): - return py.io.StdCapture(**kw) + return capture.StdCapture(**kw) def test_capturing_done_simple(self): cap = self.getcapture() @@ -756,8 +775,8 @@ out, err = cap.readouterr() assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8") - @py.test.mark.skipif('sys.version_info >= (3,)', - reason='text output different for bytes on python3') + @pytest.mark.skipif('sys.version_info >= (3,)', + reason='text output different for bytes on python3') def test_capturing_readouterr_decode_error_handling(self): cap = self.getcapture() # triggered a internal error in pytest @@ -778,7 +797,7 @@ cap = self.getcapture() print ("hello") out, err = cap.reset() - py.test.raises(ValueError, cap.reset) + pytest.raises(ValueError, cap.reset) assert out == "hello\n" assert not err @@ -788,8 +807,8 @@ cap = self.getcapture() sys.stdout.write("hello") sys.stderr.write("world") - sys.stdout = py.io.TextIO() - sys.stderr = py.io.TextIO() + sys.stdout = capture.TextIO() + sys.stderr = capture.TextIO() print ("not seen") sys.stderr.write("not seen\n") out, err = cap.reset() @@ -837,7 +856,7 @@ print ("XXX which indicates an error in the underlying capturing") print ("XXX mechanisms") cap = self.getcapture() - py.test.raises(IOError, "sys.stdin.read()") + pytest.raises(IOError, "sys.stdin.read()") out, err = cap.reset() def test_suspend_resume(self): @@ -858,18 +877,20 @@ assert out == "after\n" assert not err + class TestStdCaptureNotNow(TestStdCapture): def getcapture(self, **kw): kw['now'] = False - cap = py.io.StdCapture(**kw) + cap = capture.StdCapture(**kw) cap.startall() return cap + class TestStdCaptureFD(TestStdCapture): pytestmark = needsdup def getcapture(self, **kw): - return py.io.StdCaptureFD(**kw) + return capture.StdCaptureFD(**kw) def test_intermingling(self): cap = self.getcapture() @@ -888,10 +909,10 @@ def test_callcapture(self): def func(x, y): print (x) - py.std.sys.stderr.write(str(y)) + sys.stderr.write(str(y)) return 42 - res, out, err = py.io.StdCaptureFD.call(func, 3, y=4) + res, out, err = capture.StdCaptureFD.call(func, 3, y=4) assert res == 42 assert out.startswith("3") assert err.startswith("4") @@ -899,60 +920,67 @@ def test_many(self, capfd): def f(): for i in range(10): - cap = py.io.StdCaptureFD() + cap = capture.StdCaptureFD() cap.reset() lsof_check(f) + class TestStdCaptureFDNotNow(TestStdCaptureFD): pytestmark = needsdup def getcapture(self, **kw): kw['now'] = False - cap = py.io.StdCaptureFD(**kw) + cap = capture.StdCaptureFD(**kw) cap.startall() return cap + @needsdup def test_stdcapture_fd_tmpfile(tmpfile): - capfd = py.io.StdCaptureFD(out=tmpfile) + capfd = capture.StdCaptureFD(out=tmpfile) os.write(1, "hello".encode("ascii")) os.write(2, "world".encode("ascii")) outf, errf = capfd.done() assert outf == tmpfile + class TestStdCaptureFDinvalidFD: pytestmark = needsdup + def test_stdcapture_fd_invalid_fd(self, testdir): testdir.makepyfile(""" - import py, os + import os + from _pytest.capture import StdCaptureFD def test_stdout(): os.close(1) - cap = py.io.StdCaptureFD(out=True, err=False, in_=False) + cap = StdCaptureFD(out=True, err=False, in_=False) cap.done() def test_stderr(): os.close(2) - cap = py.io.StdCaptureFD(out=False, err=True, in_=False) + cap = StdCaptureFD(out=False, err=True, in_=False) cap.done() def test_stdin(): os.close(0) - cap = py.io.StdCaptureFD(out=False, err=False, in_=True) + cap = StdCaptureFD(out=False, err=False, in_=True) cap.done() """) result = testdir.runpytest("--capture=fd") assert result.ret == 0 assert result.parseoutcomes()['passed'] == 3 + def test_capture_not_started_but_reset(): - capsys = py.io.StdCapture(now=False) + capsys = capture.StdCapture(now=False) capsys.done() capsys.done() capsys.reset() + @needsdup def test_capture_no_sys(): - capsys = py.io.StdCapture() + capsys = capture.StdCapture() try: - cap = py.io.StdCaptureFD(patchsys=False) + cap = capture.StdCaptureFD(patchsys=False) sys.stdout.write("hello") sys.stderr.write("world") oswritebytes(1, "1") @@ -963,6 +991,7 @@ finally: capsys.reset() + @needsdup def test_callcapture_nofd(): def func(x, y): @@ -972,21 +1001,22 @@ sys.stderr.write(str(y)) return 42 - capfd = py.io.StdCaptureFD(patchsys=False) + capfd = capture.StdCaptureFD(patchsys=False) try: - res, out, err = py.io.StdCapture.call(func, 3, y=4) + res, out, err = capture.StdCapture.call(func, 3, y=4) finally: capfd.reset() assert res == 42 assert out.startswith("3") assert err.startswith("4") + @needsdup - at py.test.mark.parametrize('use', [True, False]) + at pytest.mark.parametrize('use', [True, False]) def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): if not use: tmpfile = True - cap = py.io.StdCaptureFD(out=False, err=tmpfile, now=False) + cap = capture.StdCaptureFD(out=False, err=tmpfile, now=False) cap.startall() capfile = cap.err.tmpfile cap.suspend() @@ -994,15 +1024,17 @@ capfile2 = cap.err.tmpfile assert capfile2 == capfile - at py.test.mark.parametrize('method', ['StdCapture', 'StdCaptureFD']) + + at pytest.mark.parametrize('method', ['StdCapture', 'StdCaptureFD']) def test_capturing_and_logging_fundamentals(testdir, method): if method == "StdCaptureFD" and not hasattr(os, 'dup'): - py.test.skip("need os.dup") + pytest.skip("need os.dup") # here we check a fundamental feature p = testdir.makepyfile(""" import sys, os import py, logging - cap = py.io.%s(out=False, in_=False) + from _pytest import capture + cap = capture.%s(out=False, in_=False) logging.warn("hello1") outerr = cap.suspend() https://bitbucket.org/hpk42/pytest/commits/bddf4bad6a54/ Changeset: bddf4bad6a54 User: RonnyPfannschmidt Date: 2014-01-22 19:44:20 Summary: rewrite all _pytest.capture uses of py.io to _pytest.capture Affected #: 1 file diff -r 980746ed70fb68109632d338905c4f2a5f3469ba -r bddf4bad6a5428c19b3c3a7155bf6c148a7bb317 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -29,13 +29,16 @@ method = "sys" capman = CaptureManager(method) early_config.pluginmanager.register(capman, "capturemanager") + # make sure that capturemanager is properly reset at final shutdown def teardown(): try: capman.reset_capturings() except ValueError: pass + early_config.pluginmanager.add_shutdown(teardown) + # make sure logging does not raise exceptions at the end def silence_logging_at_shutdown(): if "logging" in sys.modules: @@ -54,21 +57,27 @@ sys.stderr.write(err) raise + def addouterr(rep, outerr): for secname, content in zip(["out", "err"], outerr): if content: rep.sections.append(("Captured std%s" % secname, content)) + class NoCapture: def startall(self): pass + def resume(self): pass + def reset(self): pass + def suspend(self): return "", "" + class CaptureManager: def __init__(self, defaultmethod=None): self._method2capture = {} @@ -76,21 +85,25 @@ def _maketempfile(self): f = py.std.tempfile.TemporaryFile() - newf = py.io.dupfile(f, encoding="UTF-8") + newf = dupfile(f, encoding="UTF-8") f.close() return newf def _makestringio(self): - return py.io.TextIO() + return TextIO() def _getcapture(self, method): if method == "fd": - return py.io.StdCaptureFD(now=False, - out=self._maketempfile(), err=self._maketempfile() + return StdCaptureFD( + now=False, + out=self._maketempfile(), + err=self._maketempfile(), ) elif method == "sys": - return py.io.StdCapture(now=False, - out=self._makestringio(), err=self._makestringio() + return StdCapture( + now=False, + out=self._makestringio(), + err=self._makestringio(), ) elif method == "no": return NoCapture() @@ -105,7 +118,7 @@ method = config._conftest.rget("option_capture", path=fspath) except KeyError: method = "fd" - if method == "fd" and not hasattr(os, 'dup'): # e.g. jython + if method == "fd" and not hasattr(os, 'dup'): # e.g. jython method = "sys" return method @@ -116,12 +129,13 @@ def resumecapture_item(self, item): method = self._getmethod(item.config, item.fspath) if not hasattr(item, 'outerr'): - item.outerr = ('', '') # we accumulate outerr on the item + item.outerr = ('', '') # we accumulate outerr on the item return self.resumecapture(method) def resumecapture(self, method=None): if hasattr(self, '_capturing'): - raise ValueError("cannot resume, already capturing with %r" % + raise ValueError( + "cannot resume, already capturing with %r" % (self._capturing,)) if method is None: method = self._defaultmethod @@ -170,8 +184,9 @@ try: self.resumecapture(method) except ValueError: - return # recursive collect, XXX refactor capturing - # to allow for more lightweight recursive capturing + # recursive collect, XXX refactor capturing + # to allow for more lightweight recursive capturing + return try: rep = __multicall__.execute() finally: @@ -212,6 +227,7 @@ error_capsysfderror = "cannot use capsys and capfd at the same time" + def pytest_funcarg__capsys(request): """enables capturing of writes to sys.stdout/sys.stderr and makes captured output available via ``capsys.readouterr()`` method calls @@ -219,7 +235,8 @@ """ if "capfd" in request._funcargs: raise request.raiseerror(error_capsysfderror) - return CaptureFixture(py.io.StdCapture) + return CaptureFixture(StdCapture) + def pytest_funcarg__capfd(request): """enables capturing of writes to file descriptors 1 and 2 and makes @@ -230,7 +247,8 @@ request.raiseerror(error_capsysfderror) if not hasattr(os, 'dup'): pytest.skip("capfd funcarg needs os.dup") - return CaptureFixture(py.io.StdCaptureFD) + return CaptureFixture(StdCaptureFD) + class CaptureFixture: def __init__(self, captureclass): @@ -253,9 +271,7 @@ def close(self): self._finalize() -import os -import sys -import py + import tempfile try: @@ -263,11 +279,13 @@ except ImportError: from StringIO import StringIO -if sys.version_info < (3,0): + +if sys.version_info < (3, 0): class TextIO(StringIO): def write(self, data): if not isinstance(data, unicode): - data = unicode(data, getattr(self, '_encoding', 'UTF-8'), 'replace') + enc = getattr(self, '_encoding', 'UTF-8') + data = unicode(data, enc, 'replace') StringIO.write(self, data) else: TextIO = StringIO @@ -278,11 +296,12 @@ class BytesIO(StringIO): def write(self, data): if isinstance(data, unicode): - raise TypeError("not a byte value: %r" %(data,)) + raise TypeError("not a byte value: %r" % (data,)) StringIO.write(self, data) patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} + class FDCapture: """ Capture IO to/from a given os-level filedescriptor. """ @@ -308,7 +327,8 @@ try: os.fstat(self._savefd) except OSError: - raise ValueError("saved filedescriptor not valid, " + raise ValueError( + "saved filedescriptor not valid, " "did you call start() twice?") if self.targetfd == 0 and not self.tmpfile: fd = os.open(devnullpath, os.O_RDONLY) @@ -360,7 +380,7 @@ raise return f newfd = os.dup(fd) - if sys.version_info >= (3,0): + if sys.version_info >= (3, 0): if encoding is not None: mode = mode.replace("b", "") buffering = True @@ -371,6 +391,7 @@ return EncodedFile(f, encoding) return f + class EncodedFile(object): def __init__(self, _stream, encoding): self._stream = _stream @@ -392,6 +413,7 @@ def __getattr__(self, name): return getattr(self._stream, name) + class Capture(object): def call(cls, func, *args, **kwargs): """ return a (res, out, err) tuple where @@ -437,7 +459,7 @@ is invalid it will not be captured. """ def __init__(self, out=True, err=True, mixed=False, - in_=True, patchsys=True, now=True): + in_=True, patchsys=True, now=True): self._options = { "out": out, "err": err, @@ -458,7 +480,8 @@ patchsys = self._options['patchsys'] if in_: try: - self.in_ = FDCapture(0, tmpfile=None, now=False, + self.in_ = FDCapture( + 0, tmpfile=None, now=False, patchsys=patchsys) except OSError: pass @@ -467,8 +490,9 @@ if hasattr(out, 'write'): tmpfile = out try: - self.out = FDCapture(1, tmpfile=tmpfile, - now=False, patchsys=patchsys) + self.out = FDCapture( + 1, tmpfile=tmpfile, + now=False, patchsys=patchsys) self._options['out'] = self.out.tmpfile except OSError: pass @@ -480,8 +504,9 @@ 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 @@ -506,7 +531,7 @@ if hasattr(self, 'err') and not self.err.tmpfile.closed: errfile = self.err.done() if hasattr(self, 'in_'): - tmpfile = self.in_.done() + self.in_.done() if save: self._save() return outfile, errfile @@ -543,7 +568,7 @@ def __init__(self, out=True, err=True, in_=True, mixed=False, now=True): self._oldout = sys.stdout self._olderr = sys.stderr - self._oldin = sys.stdin + self._oldin = sys.stdin if out and not hasattr(out, 'file'): out = TextIO() self.out = out @@ -563,7 +588,7 @@ if self.err: sys.stderr = self.err if self.in_: - sys.stdin = self.in_ = DontReadFromInput() + sys.stdin = self.in_ = DontReadFromInput() def done(self, save=True): """ return (outfile, errfile) and stop capturing. """ @@ -597,6 +622,7 @@ self.err.seek(0) return out, err + class DontReadFromInput: """Temporary stub class. Ideally when stdin is accessed, the capturing should be turned off, with possibly all data captured @@ -612,11 +638,14 @@ def fileno(self): raise ValueError("redirected Stdin is pseudofile, has no fileno()") + def isatty(self): return False + def close(self): pass + try: devnullpath = os.devnull except AttributeError: https://bitbucket.org/hpk42/pytest/commits/b59593ce9e70/ Changeset: b59593ce9e70 User: RonnyPfannschmidt Date: 2014-01-22 19:48:10 Summary: simplify StdCaptureFD snapshot reading Affected #: 1 file diff -r bddf4bad6a5428c19b3c3a7155bf6c148a7bb317 -r b59593ce9e70a3670cdc53f194f89c4cead998c7 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -538,17 +538,16 @@ def readouterr(self): """ return snapshot value of stdout/stderr capturings. """ - if hasattr(self, "out"): - out = self._readsnapshot(self.out.tmpfile) + out = self._readsnapshot('out') + err = self._readsnapshot('err') + return out, err + + def _readsnapshot(self, name): + if hasattr(self, name): + f = getattr(self, name).tmpfile else: - out = "" - if hasattr(self, "err"): - err = self._readsnapshot(self.err.tmpfile) - else: - err = "" - return [out, err] + return '' - def _readsnapshot(self, f): f.seek(0) res = f.read() enc = getattr(f, "encoding", None) https://bitbucket.org/hpk42/pytest/commits/f2f6d9a2add9/ Changeset: f2f6d9a2add9 User: RonnyPfannschmidt Date: 2014-01-22 20:48:17 Summary: move imports and declarations to the top Affected #: 1 file diff -r b59593ce9e70a3670cdc53f194f89c4cead998c7 -r f2f6d9a2add9fe92223a866772d9a33f18f32a4d _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -4,9 +4,38 @@ """ import sys import os +import tempfile + import py import pytest +try: + from io import StringIO +except ImportError: + from StringIO import StringIO + +try: + from io import BytesIO +except ImportError: + class BytesIO(StringIO): + def write(self, data): + if isinstance(data, unicode): + raise TypeError("not a byte value: %r" % (data,)) + StringIO.write(self, data) + +if sys.version_info < (3, 0): + class TextIO(StringIO): + def write(self, data): + if not isinstance(data, unicode): + enc = getattr(self, '_encoding', 'UTF-8') + data = unicode(data, enc, 'replace') + StringIO.write(self, data) +else: + TextIO = StringIO + + +patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} + def pytest_addoption(parser): group = parser.getgroup("general") @@ -272,35 +301,6 @@ def close(self): self._finalize() -import tempfile - -try: - from io import StringIO -except ImportError: - from StringIO import StringIO - - -if sys.version_info < (3, 0): - class TextIO(StringIO): - def write(self, data): - if not isinstance(data, unicode): - enc = getattr(self, '_encoding', 'UTF-8') - data = unicode(data, enc, 'replace') - StringIO.write(self, data) -else: - TextIO = StringIO - -try: - from io import BytesIO -except ImportError: - class BytesIO(StringIO): - def write(self, data): - if isinstance(data, unicode): - raise TypeError("not a byte value: %r" % (data,)) - StringIO.write(self, data) - -patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} - class FDCapture: """ Capture IO to/from a given os-level filedescriptor. """ https://bitbucket.org/hpk42/pytest/commits/4ae88fa54a42/ Changeset: 4ae88fa54a42 User: RonnyPfannschmidt Date: 2014-01-22 21:03:49 Summary: kill the str magic of Encodedfile Affected #: 1 file diff -r f2f6d9a2add9fe92223a866772d9a33f18f32a4d -r 4ae88fa54a4268b32106742ab69065ddc3507361 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -400,10 +400,6 @@ def write(self, obj): if isinstance(obj, unicode): obj = obj.encode(self.encoding) - elif isinstance(obj, str): - pass - else: - obj = str(obj) self._stream.write(obj) def writelines(self, linelist): https://bitbucket.org/hpk42/pytest/commits/724a6c67551c/ Changeset: 724a6c67551c User: RonnyPfannschmidt Date: 2014-01-22 21:04:00 Summary: small cleanp Affected #: 1 file diff -r 4ae88fa54a4268b32106742ab69065ddc3507361 -r 724a6c67551c63d9ec7c44075c38182539094174 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -152,7 +152,7 @@ return method def reset_capturings(self): - for name, cap in self._method2capture.items(): + for cap in self._method2capture.values(): cap.reset() def resumecapture_item(self, item): https://bitbucket.org/hpk42/pytest/commits/f2a5abda023b/ Changeset: f2a5abda023b User: RonnyPfannschmidt Date: 2014-01-22 21:37:59 Summary: kill ancient capture devnullpath, os.devnull exists since py 2.4 Affected #: 1 file diff -r 724a6c67551c63d9ec7c44075c38182539094174 -r f2a5abda023be93ce650c8b632d46b9a7b7fa19a _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -331,7 +331,7 @@ "saved filedescriptor not valid, " "did you call start() twice?") if self.targetfd == 0 and not self.tmpfile: - fd = os.open(devnullpath, os.O_RDONLY) + fd = os.open(os.devnull, os.O_RDONLY) os.dup2(fd, 0) os.close(fd) if hasattr(self, '_oldsys'): @@ -639,12 +639,3 @@ def close(self): pass - - -try: - devnullpath = os.devnull -except AttributeError: - if os.name == 'nt': - devnullpath = 'NUL' - else: - devnullpath = '/dev/null' https://bitbucket.org/hpk42/pytest/commits/1023b4eda82d/ Changeset: 1023b4eda82d User: RonnyPfannschmidt Date: 2014-01-22 21:46:35 Summary: capture tests: move imports and declarations to the top Affected #: 1 file diff -r f2a5abda023be93ce650c8b632d46b9a7b7fa19a -r 1023b4eda82dbfdd730fedc73e26e6b4994d4267 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -6,9 +6,40 @@ from _pytest import capture from _pytest.capture import CaptureManager +from py.builtin import print_ needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')") +if sys.version_info >= (3, 0): + def tobytes(obj): + if isinstance(obj, str): + obj = obj.encode('UTF-8') + assert isinstance(obj, bytes) + return obj + + def totext(obj): + if isinstance(obj, bytes): + obj = str(obj, 'UTF-8') + assert isinstance(obj, str) + return obj +else: + def tobytes(obj): + if isinstance(obj, unicode): + obj = obj.encode('UTF-8') + assert isinstance(obj, str) + return obj + + def totext(obj): + if isinstance(obj, str): + obj = unicode(obj, 'UTF-8') + assert isinstance(obj, unicode) + return obj + + +def oswritebytes(fd, obj): + os.write(fd, tobytes(obj)) + + class TestCaptureManager: def test_getmethod_default_no_fd(self, testdir, monkeypatch): @@ -532,41 +563,6 @@ ]) -needsdup = pytest.mark.skipif("not hasattr(os, 'dup')") - -from py.builtin import print_ - - -if sys.version_info >= (3, 0): - def tobytes(obj): - if isinstance(obj, str): - obj = obj.encode('UTF-8') - assert isinstance(obj, bytes) - return obj - - def totext(obj): - if isinstance(obj, bytes): - obj = str(obj, 'UTF-8') - assert isinstance(obj, str) - return obj -else: - def tobytes(obj): - if isinstance(obj, unicode): - obj = obj.encode('UTF-8') - assert isinstance(obj, str) - return obj - - def totext(obj): - if isinstance(obj, str): - obj = unicode(obj, 'UTF-8') - assert isinstance(obj, unicode) - return obj - - -def oswritebytes(fd, obj): - os.write(fd, tobytes(obj)) - - class TestTextIO: def test_text(self): f = capture.TextIO() @@ -614,7 +610,7 @@ return f - at needsdup + at needsosdup def test_dupfile(tmpfile): flist = [] for i in range(5): @@ -661,7 +657,7 @@ class TestFDCapture: - pytestmark = needsdup + pytestmark = needsosdup def test_not_now(self, tmpfile): fd = tmpfile.fileno() @@ -887,7 +883,7 @@ class TestStdCaptureFD(TestStdCapture): - pytestmark = needsdup + pytestmark = needsosdup def getcapture(self, **kw): return capture.StdCaptureFD(**kw) @@ -926,7 +922,7 @@ class TestStdCaptureFDNotNow(TestStdCaptureFD): - pytestmark = needsdup + pytestmark = needsosdup def getcapture(self, **kw): kw['now'] = False @@ -935,7 +931,7 @@ return cap - at needsdup + at needsosdup def test_stdcapture_fd_tmpfile(tmpfile): capfd = capture.StdCaptureFD(out=tmpfile) os.write(1, "hello".encode("ascii")) @@ -945,7 +941,7 @@ class TestStdCaptureFDinvalidFD: - pytestmark = needsdup + pytestmark = needsosdup def test_stdcapture_fd_invalid_fd(self, testdir): testdir.makepyfile(""" @@ -976,7 +972,7 @@ capsys.reset() - at needsdup + at needsosdup def test_capture_no_sys(): capsys = capture.StdCapture() try: @@ -992,7 +988,7 @@ capsys.reset() - at needsdup + at needsosdup def test_callcapture_nofd(): def func(x, y): oswritebytes(1, "hello") @@ -1011,7 +1007,7 @@ assert err.startswith("4") - at needsdup + at needsosdup @pytest.mark.parametrize('use', [True, False]) def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): if not use: https://bitbucket.org/hpk42/pytest/commits/273bc8cc2296/ Changeset: 273bc8cc2296 User: RonnyPfannschmidt Date: 2014-01-22 21:50:07 Summary: add notes on the copied pylib version Affected #: 3 files diff -r 1023b4eda82dbfdd730fedc73e26e6b4994d4267 -r 273bc8cc229617800c0cbed73cbc0d1dccec5769 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,10 @@ correctly also on python2 and with pytest-xdist runs. (the fix requires py-1.4.20) +- copy, cleanup and integrate py.io capture + from pylib 1.4.20.dev2 (rev 13d9af95547e) + + 2.5.1 ----------------------------------- diff -r 1023b4eda82dbfdd730fedc73e26e6b4994d4267 -r 273bc8cc229617800c0cbed73cbc0d1dccec5769 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -2,6 +2,8 @@ per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments. """ +# note: py.io capture was where copied from +# pylib 1.4.20.dev2 (rev 13d9af95547e) import sys import os import tempfile diff -r 1023b4eda82dbfdd730fedc73e26e6b4994d4267 -r 273bc8cc229617800c0cbed73cbc0d1dccec5769 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,3 +1,5 @@ +# note: py.io capture tests where copied from +# pylib 1.4.20.dev2 (rev 13d9af95547e) from __future__ import with_statement import os import sys https://bitbucket.org/hpk42/pytest/commits/3ba17bae8538/ Changeset: 3ba17bae8538 User: RonnyPfannschmidt Date: 2014-01-22 21:52:32 Summary: stop exposing capsys/capfd.capture Affected #: 2 files diff -r 273bc8cc229617800c0cbed73cbc0d1dccec5769 -r 3ba17bae85389f17caa7a3bf0db73a09c41d0b12 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,8 @@ - copy, cleanup and integrate py.io capture from pylib 1.4.20.dev2 (rev 13d9af95547e) +- make capfd/capsys.capture private, its unused and shouldnt be exposed + 2.5.1 ----------------------------------- diff -r 273bc8cc229617800c0cbed73cbc0d1dccec5769 -r 3ba17bae85389f17caa7a3bf0db73a09c41d0b12 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -283,20 +283,20 @@ class CaptureFixture: def __init__(self, captureclass): - self.capture = captureclass(now=False) + self._capture = captureclass(now=False) def _start(self): - self.capture.startall() + self._capture.startall() def _finalize(self): if hasattr(self, 'capture'): - outerr = self._outerr = self.capture.reset() - del self.capture + outerr = self._outerr = self._capture.reset() + del self._capture return outerr def readouterr(self): try: - return self.capture.readouterr() + return self._capture.readouterr() except AttributeError: return self._outerr Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 22:16:02 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 21:16:02 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: backing out Ronny's PR because it was merged too early (still has failing tests) Message-ID: <20140122211602.19237.69772@app10.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/5ff86fc01cf5/ Changeset: 5ff86fc01cf5 User: hpk42 Date: 2014-01-22 22:15:40 Summary: backing out Ronny's PR because it was merged too early (still has failing tests) Affected #: 3 files diff -r 3ba17bae85389f17caa7a3bf0db73a09c41d0b12 -r 5ff86fc01cf5c22ff19cd9409af677f3a411c6cc CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -15,12 +15,6 @@ correctly also on python2 and with pytest-xdist runs. (the fix requires py-1.4.20) -- copy, cleanup and integrate py.io capture - from pylib 1.4.20.dev2 (rev 13d9af95547e) - -- make capfd/capsys.capture private, its unused and shouldnt be exposed - - 2.5.1 ----------------------------------- diff -r 3ba17bae85389f17caa7a3bf0db73a09c41d0b12 -r 5ff86fc01cf5c22ff19cd9409af677f3a411c6cc _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -1,55 +1,17 @@ -""" - per-test stdout/stderr capturing mechanisms, - ``capsys`` and ``capfd`` function arguments. -""" -# note: py.io capture was where copied from -# pylib 1.4.20.dev2 (rev 13d9af95547e) +""" per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments. """ + +import pytest, py import sys import os -import tempfile - -import py -import pytest - -try: - from io import StringIO -except ImportError: - from StringIO import StringIO - -try: - from io import BytesIO -except ImportError: - class BytesIO(StringIO): - def write(self, data): - if isinstance(data, unicode): - raise TypeError("not a byte value: %r" % (data,)) - StringIO.write(self, data) - -if sys.version_info < (3, 0): - class TextIO(StringIO): - def write(self, data): - if not isinstance(data, unicode): - enc = getattr(self, '_encoding', 'UTF-8') - data = unicode(data, enc, 'replace') - StringIO.write(self, data) -else: - TextIO = StringIO - - -patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} - def pytest_addoption(parser): group = parser.getgroup("general") - group._addoption( - '--capture', action="store", default=None, + group._addoption('--capture', action="store", default=None, metavar="method", 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.") - @pytest.mark.tryfirst def pytest_load_initial_conftests(early_config, parser, args, __multicall__): ns = parser.parse_known_args(args) @@ -60,16 +22,13 @@ method = "sys" capman = CaptureManager(method) early_config.pluginmanager.register(capman, "capturemanager") - # make sure that capturemanager is properly reset at final shutdown def teardown(): try: capman.reset_capturings() except ValueError: pass - early_config.pluginmanager.add_shutdown(teardown) - # make sure logging does not raise exceptions at the end def silence_logging_at_shutdown(): if "logging" in sys.modules: @@ -88,27 +47,21 @@ sys.stderr.write(err) raise - def addouterr(rep, outerr): for secname, content in zip(["out", "err"], outerr): if content: rep.sections.append(("Captured std%s" % secname, content)) - class NoCapture: def startall(self): pass - def resume(self): pass - def reset(self): pass - def suspend(self): return "", "" - class CaptureManager: def __init__(self, defaultmethod=None): self._method2capture = {} @@ -116,25 +69,21 @@ def _maketempfile(self): f = py.std.tempfile.TemporaryFile() - newf = dupfile(f, encoding="UTF-8") + newf = py.io.dupfile(f, encoding="UTF-8") f.close() return newf def _makestringio(self): - return TextIO() + return py.io.TextIO() def _getcapture(self, method): if method == "fd": - return StdCaptureFD( - now=False, - out=self._maketempfile(), - err=self._maketempfile(), + return py.io.StdCaptureFD(now=False, + out=self._maketempfile(), err=self._maketempfile() ) elif method == "sys": - return StdCapture( - now=False, - out=self._makestringio(), - err=self._makestringio(), + return py.io.StdCapture(now=False, + out=self._makestringio(), err=self._makestringio() ) elif method == "no": return NoCapture() @@ -149,24 +98,23 @@ method = config._conftest.rget("option_capture", path=fspath) except KeyError: method = "fd" - if method == "fd" and not hasattr(os, 'dup'): # e.g. jython + if method == "fd" and not hasattr(os, 'dup'): # e.g. jython method = "sys" return method def reset_capturings(self): - for cap in self._method2capture.values(): + for name, cap in self._method2capture.items(): cap.reset() def resumecapture_item(self, item): method = self._getmethod(item.config, item.fspath) if not hasattr(item, 'outerr'): - item.outerr = ('', '') # we accumulate outerr on the item + item.outerr = ('', '') # we accumulate outerr on the item return self.resumecapture(method) def resumecapture(self, method=None): if hasattr(self, '_capturing'): - raise ValueError( - "cannot resume, already capturing with %r" % + raise ValueError("cannot resume, already capturing with %r" % (self._capturing,)) if method is None: method = self._defaultmethod @@ -215,9 +163,8 @@ try: self.resumecapture(method) except ValueError: - # recursive collect, XXX refactor capturing - # to allow for more lightweight recursive capturing - return + return # recursive collect, XXX refactor capturing + # to allow for more lightweight recursive capturing try: rep = __multicall__.execute() finally: @@ -258,7 +205,6 @@ error_capsysfderror = "cannot use capsys and capfd at the same time" - def pytest_funcarg__capsys(request): """enables capturing of writes to sys.stdout/sys.stderr and makes captured output available via ``capsys.readouterr()`` method calls @@ -266,8 +212,7 @@ """ if "capfd" in request._funcargs: raise request.raiseerror(error_capsysfderror) - return CaptureFixture(StdCapture) - + return CaptureFixture(py.io.StdCapture) def pytest_funcarg__capfd(request): """enables capturing of writes to file descriptors 1 and 2 and makes @@ -278,366 +223,26 @@ request.raiseerror(error_capsysfderror) if not hasattr(os, 'dup'): pytest.skip("capfd funcarg needs os.dup") - return CaptureFixture(StdCaptureFD) - + return CaptureFixture(py.io.StdCaptureFD) class CaptureFixture: def __init__(self, captureclass): - self._capture = captureclass(now=False) + self.capture = captureclass(now=False) def _start(self): - self._capture.startall() + self.capture.startall() def _finalize(self): if hasattr(self, 'capture'): - outerr = self._outerr = self._capture.reset() - del self._capture + outerr = self._outerr = self.capture.reset() + del self.capture return outerr def readouterr(self): try: - return self._capture.readouterr() + return self.capture.readouterr() except AttributeError: return self._outerr def close(self): self._finalize() - - -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 - specified a tempfile.Tempfile() will be opened - in text mode. - """ - self.targetfd = targetfd - if tmpfile is None and targetfd != 0: - f = tempfile.TemporaryFile('wb+') - tmpfile = dupfile(f, encoding="UTF-8") - f.close() - self.tmpfile = tmpfile - self._savefd = os.dup(self.targetfd) - if patchsys: - self._oldsys = getattr(sys, patchsysdict[targetfd]) - if now: - self.start() - - def start(self): - try: - os.fstat(self._savefd) - except OSError: - raise ValueError( - "saved filedescriptor not valid, " - "did you call start() twice?") - if self.targetfd == 0 and not self.tmpfile: - fd = os.open(os.devnull, os.O_RDONLY) - os.dup2(fd, 0) - os.close(fd) - if hasattr(self, '_oldsys'): - setattr(sys, patchsysdict[self.targetfd], DontReadFromInput()) - else: - os.dup2(self.tmpfile.fileno(), self.targetfd) - if hasattr(self, '_oldsys'): - setattr(sys, patchsysdict[self.targetfd], self.tmpfile) - - def done(self): - """ unpatch and clean up, returns the self.tmpfile (file object) - """ - 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 - - def writeorg(self, data): - """ write a string to the original file descriptor - """ - tempfp = tempfile.TemporaryFile() - try: - os.dup2(self._savefd, tempfp.fileno()) - tempfp.write(data) - finally: - tempfp.close() - - -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 - 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() - mode = mode or f.mode - except AttributeError: - if raising: - raise - return f - newfd = os.dup(fd) - if sys.version_info >= (3, 0): - if encoding is not None: - mode = mode.replace("b", "") - buffering = True - return os.fdopen(newfd, mode, buffering, encoding, closefd=True) - else: - f = os.fdopen(newfd, mode, buffering) - if encoding is not None: - return EncodedFile(f, encoding) - return f - - -class EncodedFile(object): - def __init__(self, _stream, encoding): - self._stream = _stream - self.encoding = encoding - - def write(self, obj): - if isinstance(obj, unicode): - obj = obj.encode(self.encoding) - self._stream.write(obj) - - def writelines(self, linelist): - data = ''.join(linelist) - self.write(data) - - def __getattr__(self, name): - return getattr(self._stream, name) - - -class Capture(object): - def call(cls, func, *args, **kwargs): - """ return a (res, out, err) tuple where - out and err represent the output/error output - during function execution. - call the given function with args/kwargs - and capture output/error during its execution. - """ - so = cls() - try: - res = func(*args, **kwargs) - finally: - out, err = so.reset() - return res, out, err - call = classmethod(call) - - def reset(self): - """ reset sys.stdout/stderr and return captured output as strings. """ - if hasattr(self, '_reset'): - raise ValueError("was already reset") - self._reset = True - outfile, errfile = self.done(save=False) - out, err = "", "" - if outfile and not outfile.closed: - out = outfile.read() - outfile.close() - if errfile and errfile != outfile and not errfile.closed: - err = errfile.read() - errfile.close() - return out, err - - def suspend(self): - """ return current snapshot captures, memorize tempfiles. """ - outerr = self.readouterr() - outfile, errfile = self.done() - return outerr - - -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. - """ - def __init__(self, out=True, err=True, mixed=False, - in_=True, patchsys=True, now=True): - self._options = { - "out": out, - "err": err, - "mixed": mixed, - "in_": in_, - "patchsys": patchsys, - "now": now, - } - self._save() - if now: - self.startall() - - def _save(self): - in_ = self._options['in_'] - out = self._options['out'] - err = self._options['err'] - mixed = self._options['mixed'] - patchsys = self._options['patchsys'] - if in_: - try: - self.in_ = FDCapture( - 0, tmpfile=None, now=False, - patchsys=patchsys) - except OSError: - pass - if out: - tmpfile = None - if hasattr(out, 'write'): - tmpfile = out - try: - self.out = FDCapture( - 1, tmpfile=tmpfile, - now=False, patchsys=patchsys) - self._options['out'] = self.out.tmpfile - except OSError: - pass - if err: - if out and mixed: - 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._options['err'] = self.err.tmpfile - except OSError: - pass - - def startall(self): - if hasattr(self, 'in_'): - self.in_.start() - if hasattr(self, 'out'): - self.out.start() - if hasattr(self, 'err'): - self.err.start() - - def resume(self): - """ resume capturing with original temp files. """ - self.startall() - - def done(self, save=True): - """ return (outfile, errfile) and stop capturing. """ - outfile = errfile = None - if hasattr(self, 'out') and not self.out.tmpfile.closed: - outfile = self.out.done() - if hasattr(self, 'err') and not self.err.tmpfile.closed: - errfile = self.err.done() - if hasattr(self, 'in_'): - self.in_.done() - if save: - self._save() - return outfile, errfile - - def readouterr(self): - """ return snapshot value of stdout/stderr capturings. """ - out = self._readsnapshot('out') - err = self._readsnapshot('err') - return out, err - - def _readsnapshot(self, name): - if hasattr(self, name): - f = getattr(self, name).tmpfile - else: - return '' - - f.seek(0) - res = f.read() - enc = getattr(f, "encoding", None) - if enc: - res = py.builtin._totext(res, enc, "replace") - f.truncate(0) - f.seek(0) - return res - - -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). - """ - def __init__(self, out=True, err=True, in_=True, mixed=False, now=True): - self._oldout = sys.stdout - self._olderr = sys.stderr - self._oldin = sys.stdin - if out and not hasattr(out, 'file'): - out = TextIO() - self.out = out - if err: - if mixed: - err = out - elif not hasattr(err, 'write'): - err = TextIO() - self.err = err - self.in_ = in_ - if now: - self.startall() - - def startall(self): - if self.out: - sys.stdout = self.out - if self.err: - sys.stderr = self.err - if self.in_: - sys.stdin = self.in_ = DontReadFromInput() - - def done(self, save=True): - """ return (outfile, errfile) and stop capturing. """ - outfile = errfile = None - if self.out and not self.out.closed: - 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 - errfile.seek(0) - if self.in_: - sys.stdin = self._oldin - return outfile, errfile - - def resume(self): - """ resume capturing with original temp files. """ - self.startall() - - def readouterr(self): - """ return snapshot value of stdout/stderr capturings. """ - out = err = "" - if self.out: - out = self.out.getvalue() - self.out.truncate(0) - self.out.seek(0) - if self.err: - err = self.err.getvalue() - self.err.truncate(0) - self.err.seek(0) - return out, err - - -class DontReadFromInput: - """Temporary stub class. Ideally when stdin is accessed, the - capturing should be turned off, with possibly all data captured - so far sent to the screen. This should be configurable, though, - because in automated test runs it is better to crash than - hang indefinitely. - """ - def read(self, *args): - raise IOError("reading from stdin while output is captured") - readline = read - readlines = read - __iter__ = read - - def fileno(self): - raise ValueError("redirected Stdin is pseudofile, has no fileno()") - - def isatty(self): - return False - - def close(self): - pass diff -r 3ba17bae85389f17caa7a3bf0db73a09c41d0b12 -r 5ff86fc01cf5c22ff19cd9409af677f3a411c6cc testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,48 +1,8 @@ -# note: py.io capture tests where copied from -# pylib 1.4.20.dev2 (rev 13d9af95547e) -from __future__ import with_statement -import os -import sys -import py -import pytest - -from _pytest import capture +import pytest, py, os, sys from _pytest.capture import CaptureManager -from py.builtin import print_ needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')") -if sys.version_info >= (3, 0): - def tobytes(obj): - if isinstance(obj, str): - obj = obj.encode('UTF-8') - assert isinstance(obj, bytes) - return obj - - def totext(obj): - if isinstance(obj, bytes): - obj = str(obj, 'UTF-8') - assert isinstance(obj, str) - return obj -else: - def tobytes(obj): - if isinstance(obj, unicode): - obj = obj.encode('UTF-8') - assert isinstance(obj, str) - return obj - - def totext(obj): - if isinstance(obj, str): - obj = unicode(obj, 'UTF-8') - assert isinstance(obj, unicode) - return obj - - -def oswritebytes(fd, obj): - os.write(fd, tobytes(obj)) - - - class TestCaptureManager: def test_getmethod_default_no_fd(self, testdir, monkeypatch): config = testdir.parseconfig(testdir.tmpdir) @@ -74,7 +34,7 @@ @needsosdup @pytest.mark.parametrize("method", ['no', 'fd', 'sys']) def test_capturing_basic_api(self, method): - capouter = capture.StdCaptureFD() + capouter = py.io.StdCaptureFD() old = sys.stdout, sys.stderr, sys.stdin try: capman = CaptureManager() @@ -98,7 +58,7 @@ @needsosdup def test_juggle_capturings(self, testdir): - capouter = capture.StdCaptureFD() + capouter = py.io.StdCaptureFD() try: #config = testdir.parseconfig(testdir.tmpdir) capman = CaptureManager() @@ -120,11 +80,10 @@ finally: capouter.reset() - @pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") @pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_unicode(testdir, method): - if sys.version_info >= (3, 0): + if sys.version_info >= (3,0): obj = "'b\u00f6y'" else: obj = "u'\u00f6y'" @@ -141,7 +100,6 @@ "*1 passed*" ]) - @pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_bytes_in_utf8_encoding(testdir, method): testdir.makepyfile(""" @@ -153,7 +111,6 @@ "*1 passed*" ]) - def test_collect_capturing(testdir): p = testdir.makepyfile(""" print ("collect %s failure" % 13) @@ -165,7 +122,6 @@ "*collect 13 failure*", ]) - class TestPerTestCapturing: def test_capture_and_fixtures(self, testdir): p = testdir.makepyfile(""" @@ -213,6 +169,7 @@ "in teardown*", ]) + def test_no_carry_over(self, testdir): p = testdir.makepyfile(""" def test_func1(): @@ -226,6 +183,7 @@ assert "in func1" not in s assert "in func2" in s + def test_teardown_capturing(self, testdir): p = testdir.makepyfile(""" def setup_function(function): @@ -286,14 +244,13 @@ "2", ]) - class TestLoggingInteraction: def test_logging_stream_ownership(self, testdir): p = testdir.makepyfile(""" def test_logging(): import logging import pytest - stream = capture.TextIO() + stream = py.io.TextIO() logging.basicConfig(stream=stream) stream.close() # to free memory/release resources """) @@ -363,8 +320,7 @@ logging.warn("hello432") assert 0 """) - result = testdir.runpytest( - p, "--traceconfig", + result = testdir.runpytest(p, "--traceconfig", "-p", "no:capturelog") assert result.ret != 0 result.stdout.fnmatch_lines([ @@ -505,7 +461,6 @@ "*1 error*" ]) - def test_fdfuncarg_skips_on_no_osdup(testdir): testdir.makepyfile(""" import os @@ -519,7 +474,6 @@ "*1 skipped*" ]) - def test_capture_conftest_runtest_setup(testdir): testdir.makeconftest(""" def pytest_runtest_setup(): @@ -530,7 +484,6 @@ assert result.ret == 0 assert 'hello19' not in result.stdout.str() - def test_capture_early_option_parsing(testdir): testdir.makeconftest(""" def pytest_runtest_setup(): @@ -541,10 +494,9 @@ assert result.ret == 0 assert 'hello19' in result.stdout.str() - @pytest.mark.xfail(sys.version_info >= (3, 0), reason='encoding issues') def test_capture_binary_output(testdir): - testdir.makepyfile(r""" + testdir.makepyfile(""" import pytest def test_a(): @@ -563,491 +515,4 @@ result.stdout.fnmatch_lines([ '*2 passed*', ]) - - -class TestTextIO: - def test_text(self): - f = capture.TextIO() - f.write("hello") - s = f.getvalue() - assert s == "hello" - f.close() - - def test_unicode_and_str_mixture(self): - f = capture.TextIO() - if sys.version_info >= (3, 0): - f.write("\u00f6") - pytest.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))") - else: - f.write(unicode("\u00f6", 'UTF-8')) - f.write("hello") # bytes - s = f.getvalue() - f.close() - assert isinstance(s, unicode) - - -def test_bytes_io(): - f = capture.BytesIO() - f.write(tobytes("hello")) - pytest.raises(TypeError, "f.write(totext('hello'))") - s = f.getvalue() - assert s == tobytes("hello") - - -def test_dontreadfrominput(): - from _pytest.capture import DontReadFromInput - f = DontReadFromInput() - assert not f.isatty() - pytest.raises(IOError, f.read) - pytest.raises(IOError, f.readlines) - pytest.raises(IOError, iter, f) - pytest.raises(ValueError, f.fileno) - f.close() # just for completeness - - -def pytest_funcarg__tmpfile(request): - testdir = request.getfuncargvalue("testdir") - f = testdir.makepyfile("").open('wb+') - request.addfinalizer(f.close) - return f - - - at needsosdup -def test_dupfile(tmpfile): - flist = [] - for i in range(5): - nf = capture.dupfile(tmpfile, encoding="utf-8") - assert nf != tmpfile - assert nf.fileno() != tmpfile.fileno() - assert nf not in flist - print_(i, end="", file=nf) - flist.append(nf) - for i in range(5): - f = flist[i] - f.close() - tmpfile.seek(0) - s = tmpfile.read() - assert "01234" in repr(s) - tmpfile.close() - - -def test_dupfile_no_mode(): - """ - dupfile should trap an AttributeError and return f if no mode is supplied. - """ - class SomeFileWrapper(object): - "An object with a fileno method but no mode attribute" - def fileno(self): - return 1 - tmpfile = SomeFileWrapper() - assert capture.dupfile(tmpfile) is tmpfile - with pytest.raises(AttributeError): - capture.dupfile(tmpfile, raising=True) - - -def lsof_check(func): - pid = os.getpid() - try: - out = py.process.cmdexec("lsof -p %d" % pid) - except py.process.cmdexec.Error: - pytest.skip("could not run 'lsof'") - func() - out2 = py.process.cmdexec("lsof -p %d" % pid) - len1 = len([x for x in out.split("\n") if "REG" in x]) - len2 = len([x for x in out2.split("\n") if "REG" in x]) - assert len2 < len1 + 3, out2 - - -class TestFDCapture: - pytestmark = needsosdup - - def test_not_now(self, tmpfile): - fd = tmpfile.fileno() - cap = capture.FDCapture(fd, now=False) - data = tobytes("hello") - os.write(fd, data) - f = cap.done() - s = f.read() - assert not s - cap = capture.FDCapture(fd, now=False) - cap.start() - os.write(fd, data) - f = cap.done() - s = f.read() - assert s == "hello" - - def test_simple(self, tmpfile): - fd = tmpfile.fileno() - cap = capture.FDCapture(fd) - data = tobytes("hello") - os.write(fd, data) - f = cap.done() - s = f.read() - assert s == "hello" - f.close() - - def test_simple_many(self, tmpfile): - for i in range(10): - self.test_simple(tmpfile) - - def test_simple_many_check_open_files(self, tmpfile): - lsof_check(lambda: self.test_simple_many(tmpfile)) - - def test_simple_fail_second_start(self, tmpfile): - fd = tmpfile.fileno() - cap = capture.FDCapture(fd) - f = cap.done() - pytest.raises(ValueError, cap.start) - f.close() - - def test_stderr(self): - cap = capture.FDCapture(2, patchsys=True) - print_("hello", file=sys.stderr) - f = cap.done() - s = f.read() - assert s == "hello\n" - - def test_stdin(self, tmpfile): - tmpfile.write(tobytes("3")) - tmpfile.seek(0) - cap = capture.FDCapture(0, tmpfile=tmpfile) - # check with os.read() directly instead of raw_input(), because - # sys.stdin itself may be redirected (as pytest now does by default) - x = os.read(0, 100).strip() - cap.done() - assert x == tobytes("3") - - def test_writeorg(self, tmpfile): - data1, data2 = tobytes("foo"), tobytes("bar") - try: - cap = capture.FDCapture(tmpfile.fileno()) - tmpfile.write(data1) - cap.writeorg(data2) - finally: - tmpfile.close() - f = cap.done() - scap = f.read() - assert scap == totext(data1) - stmp = open(tmpfile.name, 'rb').read() - assert stmp == data2 - - -class TestStdCapture: - def getcapture(self, **kw): - return capture.StdCapture(**kw) - - def test_capturing_done_simple(self): - cap = self.getcapture() - sys.stdout.write("hello") - sys.stderr.write("world") - outfile, errfile = cap.done() - s = outfile.read() - assert s == "hello" - s = errfile.read() - assert s == "world" - - def test_capturing_reset_simple(self): - cap = self.getcapture() - print("hello world") - sys.stderr.write("hello error\n") - out, err = cap.reset() - assert out == "hello world\n" - assert err == "hello error\n" - - def test_capturing_readouterr(self): - cap = self.getcapture() - try: - print ("hello world") - sys.stderr.write("hello error\n") - out, err = cap.readouterr() - assert out == "hello world\n" - assert err == "hello error\n" - sys.stderr.write("error2") - finally: - out, err = cap.reset() - assert err == "error2" - - def test_capturing_readouterr_unicode(self): - cap = self.getcapture() - print ("hx\xc4\x85\xc4\x87") - out, err = cap.readouterr() - assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8") - - @pytest.mark.skipif('sys.version_info >= (3,)', - reason='text output different for bytes on python3') - def test_capturing_readouterr_decode_error_handling(self): - cap = self.getcapture() - # triggered a internal error in pytest - print('\xa6') - out, err = cap.readouterr() - assert out == py.builtin._totext('\ufffd\n', 'unicode-escape') - - def test_capturing_mixed(self): - cap = self.getcapture(mixed=True) - sys.stdout.write("hello ") - sys.stderr.write("world") - sys.stdout.write(".") - out, err = cap.reset() - assert out.strip() == "hello world." - assert not err - - def test_reset_twice_error(self): - cap = self.getcapture() - print ("hello") - out, err = cap.reset() - pytest.raises(ValueError, cap.reset) - assert out == "hello\n" - assert not err - - def test_capturing_modify_sysouterr_in_between(self): - oldout = sys.stdout - olderr = sys.stderr - cap = self.getcapture() - sys.stdout.write("hello") - sys.stderr.write("world") - sys.stdout = capture.TextIO() - sys.stderr = capture.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 - - def test_capturing_error_recursive(self): - cap1 = self.getcapture() - print ("cap1") - cap2 = self.getcapture() - print ("cap2") - out2, err2 = cap2.reset() - out1, err1 = cap1.reset() - assert out1 == "cap1\n" - assert out2 == "cap2\n" - - 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 - - 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 - - def test_stdin_restored(self): - old = sys.stdin - cap = self.getcapture(in_=True) - newstdin = sys.stdin - out, err = cap.reset() - assert newstdin != sys.stdin - assert sys.stdin is old - - def test_stdin_nulled_by_default(self): - print ("XXX this test may well hang instead of crashing") - print ("XXX which indicates an error in the underlying capturing") - print ("XXX mechanisms") - cap = self.getcapture() - pytest.raises(IOError, "sys.stdin.read()") - out, err = cap.reset() - - def test_suspend_resume(self): - cap = self.getcapture(out=True, err=False, in_=False) - try: - print ("hello") - sys.stderr.write("error\n") - out, err = cap.suspend() - assert out == "hello\n" - assert not err - print ("in between") - sys.stderr.write("in between\n") - cap.resume() - print ("after") - sys.stderr.write("error_after\n") - finally: - out, err = cap.reset() - assert out == "after\n" - assert not err - - -class TestStdCaptureNotNow(TestStdCapture): - def getcapture(self, **kw): - kw['now'] = False - cap = capture.StdCapture(**kw) - cap.startall() - return cap - - -class TestStdCaptureFD(TestStdCapture): - pytestmark = needsosdup - - def getcapture(self, **kw): - return capture.StdCaptureFD(**kw) - - def test_intermingling(self): - cap = self.getcapture() - oswritebytes(1, "1") - sys.stdout.write(str(2)) - sys.stdout.flush() - oswritebytes(1, "3") - oswritebytes(2, "a") - sys.stderr.write("b") - sys.stderr.flush() - oswritebytes(2, "c") - out, err = cap.reset() - assert out == "123" - assert err == "abc" - - def test_callcapture(self): - def func(x, y): - print (x) - sys.stderr.write(str(y)) - return 42 - - res, out, err = capture.StdCaptureFD.call(func, 3, y=4) - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") - - def test_many(self, capfd): - def f(): - for i in range(10): - cap = capture.StdCaptureFD() - cap.reset() - lsof_check(f) - - -class TestStdCaptureFDNotNow(TestStdCaptureFD): - pytestmark = needsosdup - - def getcapture(self, **kw): - kw['now'] = False - cap = capture.StdCaptureFD(**kw) - cap.startall() - return cap - - - at needsosdup -def test_stdcapture_fd_tmpfile(tmpfile): - capfd = capture.StdCaptureFD(out=tmpfile) - os.write(1, "hello".encode("ascii")) - os.write(2, "world".encode("ascii")) - outf, errf = capfd.done() - assert outf == tmpfile - - -class TestStdCaptureFDinvalidFD: - pytestmark = needsosdup - - def test_stdcapture_fd_invalid_fd(self, testdir): - testdir.makepyfile(""" - import os - from _pytest.capture import StdCaptureFD - def test_stdout(): - os.close(1) - cap = StdCaptureFD(out=True, err=False, in_=False) - cap.done() - def test_stderr(): - os.close(2) - cap = StdCaptureFD(out=False, err=True, in_=False) - cap.done() - def test_stdin(): - os.close(0) - cap = StdCaptureFD(out=False, err=False, in_=True) - cap.done() - """) - result = testdir.runpytest("--capture=fd") - assert result.ret == 0 - assert result.parseoutcomes()['passed'] == 3 - - -def test_capture_not_started_but_reset(): - capsys = capture.StdCapture(now=False) - capsys.done() - capsys.done() - capsys.reset() - - - at needsosdup -def test_capture_no_sys(): - capsys = capture.StdCapture() - try: - cap = capture.StdCaptureFD(patchsys=False) - sys.stdout.write("hello") - sys.stderr.write("world") - oswritebytes(1, "1") - oswritebytes(2, "2") - out, err = cap.reset() - assert out == "1" - assert err == "2" - finally: - capsys.reset() - - - at needsosdup -def test_callcapture_nofd(): - def func(x, y): - oswritebytes(1, "hello") - oswritebytes(2, "hello") - print (x) - sys.stderr.write(str(y)) - return 42 - - capfd = capture.StdCaptureFD(patchsys=False) - try: - res, out, err = capture.StdCapture.call(func, 3, y=4) - finally: - capfd.reset() - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") - - - at needsosdup - at pytest.mark.parametrize('use', [True, False]) -def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): - if not use: - tmpfile = True - cap = capture.StdCaptureFD(out=False, err=tmpfile, now=False) - cap.startall() - capfile = cap.err.tmpfile - cap.suspend() - cap.resume() - capfile2 = cap.err.tmpfile - assert capfile2 == capfile - - - at pytest.mark.parametrize('method', ['StdCapture', 'StdCaptureFD']) -def test_capturing_and_logging_fundamentals(testdir, method): - if method == "StdCaptureFD" and not hasattr(os, 'dup'): - pytest.skip("need os.dup") - # here we check a fundamental feature - p = testdir.makepyfile(""" - import sys, os - import py, logging - from _pytest import capture - cap = capture.%s(out=False, in_=False) - - logging.warn("hello1") - outerr = cap.suspend() - print ("suspend, captured %%s" %%(outerr,)) - logging.warn("hello2") - - cap.resume() - logging.warn("hello3") - - outerr = cap.suspend() - print ("suspend2, captured %%s" %% (outerr,)) - """ % (method,)) - result = testdir.runpython(p) - result.stdout.fnmatch_lines([ - "suspend, captured*hello1*", - "suspend2, captured*hello2*WARNING:root:hello3*", - ]) - assert "atexit" not in result.stderr.str() + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 22 22:18:39 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 21:18:39 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: mark encoding test as xfail also on py2 Message-ID: <20140122211839.22967.12411@app01.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/634ccdf8a274/ Changeset: 634ccdf8a274 User: hpk42 Date: 2014-01-22 22:18:33 Summary: mark encoding test as xfail also on py2 Affected #: 1 file diff -r 5ff86fc01cf5c22ff19cd9409af677f3a411c6cc -r 634ccdf8a2747cc3f662f4bacf1d25047c62a7bc testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -494,7 +494,7 @@ assert result.ret == 0 assert 'hello19' in result.stdout.str() - at pytest.mark.xfail(sys.version_info >= (3, 0), reason='encoding issues') + at pytest.mark.xfail(reason='encoding issues') def test_capture_binary_output(testdir): testdir.makepyfile(""" import pytest @@ -515,4 +515,4 @@ result.stdout.fnmatch_lines([ '*2 passed*', ]) - + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 00:53:00 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 23:53:00 -0000 Subject: [Pytest-commit] commit/pytest: 5 new changesets Message-ID: <20140122235300.10361.11200@app05.ash-private.bitbucket.org> 5 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/ee75804c7e18/ Changeset: ee75804c7e18 Branch: contributiondocs User: pbanaszkiewicz Date: 2014-01-22 11:24:58 Summary: New enthusiastic contribution guide based on Audreyr's cookiecutter-pypackage Audrey's code is BSD, so there should be no problem with licensing. I've covered: * contribution types (with hints) * steps to start with pytest development * testing pytest * basics of hg Affected #: 2 files diff -r 7e50e96912a21240cc8dcd65a3c1fcf2e0b9cd6c -r ee75804c7e18a8870c1b86b93099f69a70cef5bf doc/en/contents.txt --- a/doc/en/contents.txt +++ b/doc/en/contents.txt @@ -16,7 +16,7 @@ plugins example/index talks - develop + contribute funcarg_compare.txt announce/index diff -r 7e50e96912a21240cc8dcd65a3c1fcf2e0b9cd6c -r ee75804c7e18a8870c1b86b93099f69a70cef5bf doc/en/contribute.txt --- /dev/null +++ b/doc/en/contribute.txt @@ -0,0 +1,122 @@ +.. _contributing: + +============ +Contributing +============ + +Contributions are highly welcomed and appreciated. Every little help counts, +so do not hesitate! + +Types of contributions +====================== + +Submit feedback for developers +------------------------------ + +Do you like py.test? Share some love on Twitter or in your blog posts! + +We'd also like to hear about your propositions and suggestions. Feel free to +submit them as issues `here `__ and: + +* Set the "kind" to "enhancement" or "proposal" so that we can quickly find + about them. +* Explain in detail how they should work. +* Keep the scope as narrow as possible. This will make it easier to implement. +* If you have required skills and/or knowledge, you can always contribute to + these issues! + +Report bugs +----------- + +Report bugs at https://bitbucket.org/hpk42/pytest/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting, + specifically Python interpreter version, + installed libraries and py.test version. +* Detailed steps to reproduce the bug. + +Fix bugs +-------- + +Look through the BitBucket issues for bugs. Here is sample filter you can use: +https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=bug + +:ref:'Talk ' to developers to find out how you can fix specific bugs. + +Implement features +------------------ + +Look through the BitBucket issues for enhancements. Here is sample filter you +can use: +https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=enhancement + +:ref:'Talk ' to developers to find out how you can implement specific +features. + +Write documentation +------------------- + +py.test could always use more documentation. What exactly is needed? + +* More complementary documentation. Have you perhaps found something unclear? +* Documentation translations. We currently have English and Japanese versions. +* Docstrings. There's never too much of them. +* Blog posts, articles and such -- they're all very appreciated. + +Getting started for contributing +================================ + +1. Fork the py.test repository on BitBucket. +.. _checkout: +2. Clone your fork locally:: + + $ hg clone ssh://hg at bitbucket.org/your_name_here/pytest + +3. Install your local copy into a virtualenv. Assuming you have + ``virtualenvwrapper`` (http://virtualenvwrapper.readthedocs.org) installed:: + + $ mkvirtualenv pytest + $ cd pytest/ + $ python setup.py develop + + If that last command complains about not finding the required version + of "py" then you need to use the development pypi repository:: + + $ python setup.py develop -i http://pypi.testrun.org + +4. Create a branch for local development:: + + $ hg branch name-of-your-bugfix-or-feature + + Now you can make your changes locally. + +5. When you're done making changes, check that all of them pass all the tests + (including PEP8 and different Python interpreter versions). It's as simple + as issuing this one command:: + + $ tox + + The least minimum of required Python tests to pass is Python 2.7 and + Python 3.3:: + + $ tox -e py27,py33 + + If you don't seem to have ``tox`` installed, issue this from inside your + virtualenv:: + + $ pip install tox + + You also need to have Python 3.3 and 2.7 available in your system. + +6. Commit your changes and push your branch to BitBucket:: + + $ hg add . + $ hg commit + $ hg push --new-branch -r . + +7. Submit a pull request through the BitBucket website. + +.. include:: links.inc https://bitbucket.org/hpk42/pytest/commits/31b8815aa355/ Changeset: 31b8815aa355 Branch: contributiondocs User: pbanaszkiewicz Date: 2014-01-22 11:37:02 Summary: Moved contribution guide to the rootdir/CONTRIBUTING.txt Affected #: 2 files diff -r ee75804c7e18a8870c1b86b93099f69a70cef5bf -r 31b8815aa355ea06f16269758205cd3f9b8a5d00 CONTRIBUTING.txt --- /dev/null +++ b/CONTRIBUTING.txt @@ -0,0 +1,119 @@ + +============ +Contributing +============ + +Contributions are highly welcomed and appreciated. Every little help counts, +so do not hesitate! + +Types of contributions +====================== + +Submit feedback for developers +------------------------------ + +Do you like py.test? Share some love on Twitter or in your blog posts! + +We'd also like to hear about your propositions and suggestions. Feel free to +submit them as issues `here `__ and: + +* Set the "kind" to "enhancement" or "proposal" so that we can quickly find + about them. +* Explain in detail how they should work. +* Keep the scope as narrow as possible. This will make it easier to implement. +* If you have required skills and/or knowledge, you can always contribute to + these issues! + +Report bugs +----------- + +Report bugs at https://bitbucket.org/hpk42/pytest/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting, + specifically Python interpreter version, + installed libraries and py.test version. +* Detailed steps to reproduce the bug. + +Fix bugs +-------- + +Look through the BitBucket issues for bugs. Here is sample filter you can use: +https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=bug + +:ref:'Talk ' to developers to find out how you can fix specific bugs. + +Implement features +------------------ + +Look through the BitBucket issues for enhancements. Here is sample filter you +can use: +https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=enhancement + +:ref:'Talk ' to developers to find out how you can implement specific +features. + +Write documentation +------------------- + +py.test could always use more documentation. What exactly is needed? + +* More complementary documentation. Have you perhaps found something unclear? +* Documentation translations. We currently have English and Japanese versions. +* Docstrings. There's never too much of them. +* Blog posts, articles and such -- they're all very appreciated. + +Getting started for contributing +================================ + +1. Fork the py.test repository on BitBucket. +.. _checkout: +2. Clone your fork locally:: + + $ hg clone ssh://hg at bitbucket.org/your_name_here/pytest + +3. Install your local copy into a virtualenv. Assuming you have + ``virtualenvwrapper`` (http://virtualenvwrapper.readthedocs.org) installed:: + + $ mkvirtualenv pytest + $ cd pytest/ + $ python setup.py develop + + If that last command complains about not finding the required version + of "py" then you need to use the development pypi repository:: + + $ python setup.py develop -i http://pypi.testrun.org + +4. Create a branch for local development:: + + $ hg branch name-of-your-bugfix-or-feature + + Now you can make your changes locally. + +5. When you're done making changes, check that all of them pass all the tests + (including PEP8 and different Python interpreter versions). It's as simple + as issuing this one command:: + + $ tox + + The least minimum of required Python tests to pass is Python 2.7 and + Python 3.3:: + + $ tox -e py27,py33 + + If you don't seem to have ``tox`` installed, issue this from inside your + virtualenv:: + + $ pip install tox + + You also need to have Python 3.3 and 2.7 available in your system. + +6. Commit your changes and push your branch to BitBucket:: + + $ hg add . + $ hg commit + $ hg push --new-branch -r . + +7. Submit a pull request through the BitBucket website. diff -r ee75804c7e18a8870c1b86b93099f69a70cef5bf -r 31b8815aa355ea06f16269758205cd3f9b8a5d00 doc/en/contribute.txt --- a/doc/en/contribute.txt +++ b/doc/en/contribute.txt @@ -1,122 +1,3 @@ .. _contributing: -============ -Contributing -============ - -Contributions are highly welcomed and appreciated. Every little help counts, -so do not hesitate! - -Types of contributions -====================== - -Submit feedback for developers ------------------------------- - -Do you like py.test? Share some love on Twitter or in your blog posts! - -We'd also like to hear about your propositions and suggestions. Feel free to -submit them as issues `here `__ and: - -* Set the "kind" to "enhancement" or "proposal" so that we can quickly find - about them. -* Explain in detail how they should work. -* Keep the scope as narrow as possible. This will make it easier to implement. -* If you have required skills and/or knowledge, you can always contribute to - these issues! - -Report bugs ------------ - -Report bugs at https://bitbucket.org/hpk42/pytest/issues. - -If you are reporting a bug, please include: - -* Your operating system name and version. -* Any details about your local setup that might be helpful in troubleshooting, - specifically Python interpreter version, - installed libraries and py.test version. -* Detailed steps to reproduce the bug. - -Fix bugs --------- - -Look through the BitBucket issues for bugs. Here is sample filter you can use: -https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=bug - -:ref:'Talk ' to developers to find out how you can fix specific bugs. - -Implement features ------------------- - -Look through the BitBucket issues for enhancements. Here is sample filter you -can use: -https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=enhancement - -:ref:'Talk ' to developers to find out how you can implement specific -features. - -Write documentation -------------------- - -py.test could always use more documentation. What exactly is needed? - -* More complementary documentation. Have you perhaps found something unclear? -* Documentation translations. We currently have English and Japanese versions. -* Docstrings. There's never too much of them. -* Blog posts, articles and such -- they're all very appreciated. - -Getting started for contributing -================================ - -1. Fork the py.test repository on BitBucket. -.. _checkout: -2. Clone your fork locally:: - - $ hg clone ssh://hg at bitbucket.org/your_name_here/pytest - -3. Install your local copy into a virtualenv. Assuming you have - ``virtualenvwrapper`` (http://virtualenvwrapper.readthedocs.org) installed:: - - $ mkvirtualenv pytest - $ cd pytest/ - $ python setup.py develop - - If that last command complains about not finding the required version - of "py" then you need to use the development pypi repository:: - - $ python setup.py develop -i http://pypi.testrun.org - -4. Create a branch for local development:: - - $ hg branch name-of-your-bugfix-or-feature - - Now you can make your changes locally. - -5. When you're done making changes, check that all of them pass all the tests - (including PEP8 and different Python interpreter versions). It's as simple - as issuing this one command:: - - $ tox - - The least minimum of required Python tests to pass is Python 2.7 and - Python 3.3:: - - $ tox -e py27,py33 - - If you don't seem to have ``tox`` installed, issue this from inside your - virtualenv:: - - $ pip install tox - - You also need to have Python 3.3 and 2.7 available in your system. - -6. Commit your changes and push your branch to BitBucket:: - - $ hg add . - $ hg commit - $ hg push --new-branch -r . - -7. Submit a pull request through the BitBucket website. - -.. include:: links.inc +.. include:: ../../CONTRIBUTING.txt https://bitbucket.org/hpk42/pytest/commits/4458fd656dc2/ Changeset: 4458fd656dc2 Branch: contributiondocs User: pbanaszkiewicz Date: 2014-01-22 12:19:33 Summary: Addressed contribution guide issues: virtualenv, links, Github mirror, RST rendering Affected #: 1 file diff -r 31b8815aa355ea06f16269758205cd3f9b8a5d00 -r 4458fd656dc2b6c9476fa19fa739692d927b5168 CONTRIBUTING.txt --- a/CONTRIBUTING.txt +++ b/CONTRIBUTING.txt @@ -43,7 +43,7 @@ Look through the BitBucket issues for bugs. Here is sample filter you can use: https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=bug -:ref:'Talk ' to developers to find out how you can fix specific bugs. +:ref:`Talk ` to developers to find out how you can fix specific bugs. Implement features ------------------ @@ -52,7 +52,7 @@ can use: https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=enhancement -:ref:'Talk ' to developers to find out how you can implement specific +:ref:`Talk ` to developers to find out how you can implement specific features. Write documentation @@ -68,16 +68,29 @@ Getting started for contributing ================================ -1. Fork the py.test repository on BitBucket. +The primary development platform for py.test is BitBucket. You can find all +the issues there and submit pull requests. There is, however, +a `GitHub mirror `__ available, too, +although it only allows for submitting pull requests. For a GitHub +contribution guide look :ref:`below `. + +1. Fork the py.test `repository `__ on BitBucket. + +2. Create a local virtualenv (http://www.virtualenv.org/en/latest/):: + + $ virtualenv pytest-venv + $ cd pytest-venv/ + .. _checkout: -2. Clone your fork locally:: + +3. Clone your fork locally:: $ hg clone ssh://hg at bitbucket.org/your_name_here/pytest -3. Install your local copy into a virtualenv. Assuming you have - ``virtualenvwrapper`` (http://virtualenvwrapper.readthedocs.org) installed:: +.. _installing-dev-pytest: - $ mkvirtualenv pytest +4. Install your local copy into a virtualenv:: + $ cd pytest/ $ python setup.py develop @@ -86,11 +99,7 @@ $ python setup.py develop -i http://pypi.testrun.org -4. Create a branch for local development:: - - $ hg branch name-of-your-bugfix-or-feature - - Now you can make your changes locally. +.. _testing-pytest: 5. When you're done making changes, check that all of them pass all the tests (including PEP8 and different Python interpreter versions). It's as simple @@ -110,10 +119,41 @@ You also need to have Python 3.3 and 2.7 available in your system. -6. Commit your changes and push your branch to BitBucket:: +6. Commit your changes and push to BitBucket:: $ hg add . $ hg commit - $ hg push --new-branch -r . + $ hg push -r . 7. Submit a pull request through the BitBucket website. + + +.. _contribution-on-github: +What about GitHub? +------------------ + +.. warning:: + Remember that GitHub is **not** a default development platform for py.test + and it doesn't include e.g. issue list. + +1. Fork the py.test `repository `__ on GitHub. + +2. Create a local virtualenv (http://www.virtualenv.org/en/latest/):: + + $ virtualenv pytest-venv + $ cd pytest-venv/ + +3. Clone your fork locally:: + + $ git clone git at github.com:your_name_here/pytest.git + +4. :ref:`Install your local copy into a virtualenv ` + and after that :ref:`test your changes `. + +5. Commit your changes and push to GitHub:: + + $ git add . + $ git commit + $ git push -u + +6. Submit a pull request through the GitHub website. https://bitbucket.org/hpk42/pytest/commits/8fefd50ec004/ Changeset: 8fefd50ec004 Branch: contributiondocs User: pbanaszkiewicz Date: 2014-01-22 17:05:11 Summary: Contribution guide: moved tox inst. instructions up Affected #: 1 file diff -r 4458fd656dc2b6c9476fa19fa739692d927b5168 -r 8fefd50ec0044a336f235a63369bf802723895bd CONTRIBUTING.txt --- a/CONTRIBUTING.txt +++ b/CONTRIBUTING.txt @@ -102,22 +102,20 @@ .. _testing-pytest: 5. When you're done making changes, check that all of them pass all the tests - (including PEP8 and different Python interpreter versions). It's as simple - as issuing this one command:: + (including PEP8 and different Python interpreter versions). First install + ``tox``:: - $ tox + $ pip install tox - The least minimum of required Python tests to pass is Python 2.7 and - Python 3.3:: + You also need to have Python 2.7 and 3.3 available in your system. Now + running tests is as simple as issuing this one command:: $ tox -e py27,py33 - If you don't seem to have ``tox`` installed, issue this from inside your - virtualenv:: + This command will run tests for both Python 2.7 and 3.3, which is a minimum + required to get your patch merged. To run whole test suit issue:: - $ pip install tox - - You also need to have Python 3.3 and 2.7 available in your system. + $ tox 6. Commit your changes and push to BitBucket:: https://bitbucket.org/hpk42/pytest/commits/506a2abc6144/ Changeset: 506a2abc6144 User: bubenkoff Date: 2014-01-23 00:52:49 Summary: merge pbanaszkiewicz/contributiondocs Affected #: 3 files diff -r 634ccdf8a2747cc3f662f4bacf1d25047c62a7bc -r 506a2abc6144bef2cfb8be6b6210acf1c964a9b0 CONTRIBUTING.rst --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,161 @@ + +============ +Contributing +============ + +Contributions are highly welcomed and appreciated. Every little help counts, +so do not hesitate! + +Types of contributions +====================== + +Submit feedback for developers +------------------------------ + +Do you like py.test? Share some love on Twitter or in your blog posts! + +We'd also like to hear about your propositions and suggestions. Feel free to +submit them as issues `here `__ and: + +* Set the "kind" to "enhancement" or "proposal" so that we can quickly find + about them. +* Explain in detail how they should work. +* Keep the scope as narrow as possible. This will make it easier to implement. +* If you have required skills and/or knowledge, you can always contribute to + these issues! + +Report bugs +----------- + +Report bugs at https://bitbucket.org/hpk42/pytest/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting, + specifically Python interpreter version, + installed libraries and py.test version. +* Detailed steps to reproduce the bug. + +Fix bugs +-------- + +Look through the BitBucket issues for bugs. Here is sample filter you can use: +https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=bug + +:ref:`Talk ` to developers to find out how you can fix specific bugs. + +Implement features +------------------ + +Look through the BitBucket issues for enhancements. Here is sample filter you +can use: +https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=enhancement + +:ref:`Talk ` to developers to find out how you can implement specific +features. + +Write documentation +------------------- + +py.test could always use more documentation. What exactly is needed? + +* More complementary documentation. Have you perhaps found something unclear? +* Documentation translations. We currently have English and Japanese versions. +* Docstrings. There's never too much of them. +* Blog posts, articles and such -- they're all very appreciated. + +Getting started for contributing +================================ + +The primary development platform for py.test is BitBucket. You can find all +the issues there and submit pull requests. There is, however, +a `GitHub mirror `__ available, too, +although it only allows for submitting pull requests. For a GitHub +contribution guide look :ref:`below `. + +1. Fork the py.test `repository `__ on BitBucket. + +2. Create a local virtualenv (http://www.virtualenv.org/en/latest/):: + + $ virtualenv pytest-venv + $ cd pytest-venv/ + $ source bin/activate + +.. _checkout: + +3. Clone your fork locally:: + + $ hg clone ssh://hg at bitbucket.org/your_name_here/pytest + +.. _installing-dev-pytest: + +4. Install your local copy into a virtualenv:: + + $ cd pytest/ + $ python setup.py develop + + If that last command complains about not finding the required version + of "py" then you need to use the development pypi repository:: + + $ python setup.py develop -i http://pypi.testrun.org + +.. _testing-pytest: + +5. When you're done making changes, check that all of them pass all the tests + (including PEP8 and different Python interpreter versions). First install + ``tox``:: + + $ pip install tox + + You also need to have Python 2.7 and 3.3 available in your system. Now + running tests is as simple as issuing this one command:: + + $ tox -e py27,py33 + + This command will run tests for both Python 2.7 and 3.3, which is a minimum + required to get your patch merged. To run whole test suit issue:: + + $ tox + +6. Commit your changes and push to BitBucket:: + + $ hg branch + $ hg add . + $ hg commit -m" + $ hg push -b . + +7. Submit a pull request through the BitBucket website. + + +.. _contribution-on-github: +What about GitHub? +------------------ + +.. warning:: + Remember that GitHub is **not** a default development platform for py.test + and it doesn't include e.g. issue list. + +1. Fork the py.test `repository `__ on GitHub. + +2. Create a local virtualenv (http://www.virtualenv.org/en/latest/):: + + $ virtualenv pytest-venv + $ cd pytest-venv/ + +3. Clone your fork locally:: + + $ git clone git at github.com:your_name_here/pytest.git + +4. :ref:`Install your local copy into a virtualenv ` + and after that :ref:`test your changes `. + +5. Commit your changes and push to GitHub:: + + $ git branch + $ git checkout + $ git add . + $ git commit -am"" + $ git push origin + +6. Submit a pull request through the GitHub website. diff -r 634ccdf8a2747cc3f662f4bacf1d25047c62a7bc -r 506a2abc6144bef2cfb8be6b6210acf1c964a9b0 doc/en/contents.txt --- a/doc/en/contents.txt +++ b/doc/en/contents.txt @@ -16,7 +16,7 @@ plugins example/index talks - develop + contribute funcarg_compare.txt announce/index diff -r 634ccdf8a2747cc3f662f4bacf1d25047c62a7bc -r 506a2abc6144bef2cfb8be6b6210acf1c964a9b0 doc/en/contribute.txt --- /dev/null +++ b/doc/en/contribute.txt @@ -0,0 +1,3 @@ +.. _contributing: + +.. include:: ../../CONTRIBUTING.rst Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 00:54:32 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 22 Jan 2014 23:54:32 -0000 Subject: [Pytest-commit] commit/pytest: bubenkoff: add Piotr Banaszkiewicz Message-ID: <20140122235432.1567.96734@app11.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/60052491d38b/ Changeset: 60052491d38b User: bubenkoff Date: 2014-01-23 00:54:25 Summary: add Piotr Banaszkiewicz Affected #: 1 file diff -r 506a2abc6144bef2cfb8be6b6210acf1c964a9b0 -r 60052491d38bf3fd68909c35aa04e063415fe2b6 AUTHORS --- a/AUTHORS +++ b/AUTHORS @@ -1,7 +1,7 @@ Holger Krekel, holger at merlinux eu merlinux GmbH, Germany, office at merlinux eu -Contributors include:: +Contributors include:: Ronny Pfannschmidt Benjamin Peterson @@ -9,21 +9,21 @@ Jason R. Coombs Wouter van Ackooy Samuele Pedroni -Anatoly Bubenkoff +Anatoly Bubenkoff Brianna Laugher Carl Friedrich Bolz Armin Rigo Maho -Jaap Broekhuizen +Jaap Broekhuizen Maciek Fijalkowski Guido Wesdorp Brian Dorsey Ross Lawley Ralf Schmitt -Chris Lamb +Chris Lamb Harald Armin Massa Martijn Faassen -Ian Bicking +Ian Bicking Jan Balster Grig Gheorghiu Bob Ippolito @@ -36,3 +36,4 @@ Christian Theunert Anthon van der Neut Mark Abramowitz +Piotr Banaszkiewicz Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 01:09:34 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 00:09:34 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140123000934.32598.81168@app03.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/9545ee037ecb/ Changeset: 9545ee037ecb User: jurko Date: 2014-01-15 19:30:03 Summary: document explicitly clearing local references to pytest.raises() results pytest.raises() returns an ExceptionInfo object which, if a local reference is made to it, forms a reference cycle: ExceptionInfo --> exception --> stack frame raising the exception --> current stack frame --> current local variables --> Exception Info Such a reference cycle would then prevent any local variables in the current stack frame, or any of its child stack frames involved in the same reference cycle, from being garbage collected until the next reference cycle garbage collection phase. This unnecessarily increases the program's memory footprint and potentially slows it down. This situation is based on a similar one described in the official 'try' statement Python documentation for locally stored exception references. Affected #: 1 file diff -r 0bf4880a178da71d44ba91d844e68165c83f2562 -r 9545ee037ecb9de2177a1ee0ba4e50bfa181adac _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -938,6 +938,12 @@ This helper produces a ``py.code.ExceptionInfo()`` object. + Note that any local references made to such returned + ``py.code.ExceptionInfo()`` objects should be explicitly cleared, as they + are part of a reference cycle similar to local references to caught Python + exception objects. See the official Python ``try`` statement documentation + for more detailed information. + If using Python 2.5 or above, you may use this function as a context manager:: https://bitbucket.org/hpk42/pytest/commits/bdc540368ddf/ Changeset: bdc540368ddf User: bubenkoff Date: 2014-01-23 01:09:30 Summary: Merged in jurko/pytest (pull request #98) document explicitly clearing local references to pytest.raises() results Affected #: 3 files diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r bdc540368ddfd4dcfb0558625b4caba02355b812 /contribute.txt --- /dev/null +++ b//contribute.txt @@ -0,0 +1,3 @@ +.. _contributing: + +.. include:: ../../CONTRIBUTING.rst diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r bdc540368ddfd4dcfb0558625b4caba02355b812 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -938,6 +938,12 @@ This helper produces a ``py.code.ExceptionInfo()`` object. + Note that any local references made to such returned + ``py.code.ExceptionInfo()`` objects should be explicitly cleared, as they + are part of a reference cycle similar to local references to caught Python + exception objects. See the official Python ``try`` statement documentation + for more detailed information. + If using Python 2.5 or above, you may use this function as a context manager:: diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r bdc540368ddfd4dcfb0558625b4caba02355b812 doc/en/contribute.txt --- a/doc/en/contribute.txt +++ /dev/null @@ -1,3 +0,0 @@ -.. _contributing: - -.. include:: ../../CONTRIBUTING.rst Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 01:16:13 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 00:16:13 -0000 Subject: [Pytest-commit] commit/pytest: bubenkoff: add contribute.txt back Message-ID: <20140123001613.22776.55213@app09.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/fd5ac46aca5c/ Changeset: fd5ac46aca5c User: bubenkoff Date: 2014-01-23 01:16:06 Summary: add contribute.txt back Affected #: 1 file diff -r bdc540368ddfd4dcfb0558625b4caba02355b812 -r fd5ac46aca5c1b5596f4acd0e91bd9236906c59c doc/en/contribute.txt --- /dev/null +++ b/doc/en/contribute.txt @@ -0,0 +1,3 @@ +.. _contributing: + +.. include:: ../../CONTRIBUTING.rst Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 01:28:09 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 00:28:09 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140123002809.1543.13636@app07.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/bf25d089758b/ Changeset: bf25d089758b User: bubenkoff Date: 2014-01-23 01:24:59 Summary: revert merge Affected #: 1 file diff -r fd5ac46aca5c1b5596f4acd0e91bd9236906c59c -r bf25d089758b4dcc64147c331c86ec12a5ceaf4b _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -938,12 +938,6 @@ This helper produces a ``py.code.ExceptionInfo()`` object. - Note that any local references made to such returned - ``py.code.ExceptionInfo()`` objects should be explicitly cleared, as they - are part of a reference cycle similar to local references to caught Python - exception objects. See the official Python ``try`` statement documentation - for more detailed information. - If using Python 2.5 or above, you may use this function as a context manager:: https://bitbucket.org/hpk42/pytest/commits/204b1dcb1973/ Changeset: 204b1dcb1973 User: bubenkoff Date: 2014-01-23 01:28:01 Summary: document explicitly clearing local references to pytest.raises() results Affected #: 1 file diff -r bf25d089758b4dcc64147c331c86ec12a5ceaf4b -r 204b1dcb1973fedeb5bf33f28b306467868ff566 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -938,6 +938,12 @@ This helper produces a ``py.code.ExceptionInfo()`` object. + Note that any local references made to such returned + ``py.code.ExceptionInfo()`` objects should be explicitly cleared, as they + are part of a reference cycle similar to local references to caught Python + exception objects. See the official Python ``try`` statement documentation + for more detailed information. + If using Python 2.5 or above, you may use this function as a context manager:: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 01:44:40 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 00:44:40 -0000 Subject: [Pytest-commit] commit/pytest: bubenkoff: revert merge Message-ID: <20140123004440.1438.53712@app11.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/1f205c38ddad/ Changeset: 1f205c38ddad User: bubenkoff Date: 2014-01-23 01:44:32 Summary: revert merge Affected #: 1 file diff -r 204b1dcb1973fedeb5bf33f28b306467868ff566 -r 1f205c38ddadf998343ecdcf62ddfafa97378df9 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -938,12 +938,6 @@ This helper produces a ``py.code.ExceptionInfo()`` object. - Note that any local references made to such returned - ``py.code.ExceptionInfo()`` objects should be explicitly cleared, as they - are part of a reference cycle similar to local references to caught Python - exception objects. See the official Python ``try`` statement documentation - for more detailed information. - If using Python 2.5 or above, you may use this function as a context manager:: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 08:48:41 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 07:48:41 -0000 Subject: [Pytest-commit] commit/tox: hpk42: fix issue140: depend on virtualenv>=1.11.1 Message-ID: <20140123074841.17062.69713@app09.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/9dce275b9bbd/ Changeset: 9dce275b9bbd User: hpk42 Date: 2014-01-23 08:48:15 Summary: fix issue140: depend on virtualenv>=1.11.1 Affected #: 5 files diff -r ab3ca2815135d40e27f17c6fdfe616cbbdecd50a -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ -1.6.2.dev +1.7.0.dev --------- +- don't lookup "pip-script" anymore but rather just "pip" on windows + as this is a pip implementation detail and changed with pip-1.5. + It might mean that tox-1.7 is not able to install a different pip + version into a virtualenv anymore. + - drop Python2.5 compatibility because it became too hard due to the setuptools-2.0 dropping support. tox now has no support for creating python2.5 based environments anymore @@ -22,10 +27,11 @@ to allow installation of tox via easy_install/eggs. Thanks Jenisys. -- fix issue126: depend on virtualenv>=1.10.1 so that we can rely +- fix issue126: depend on virtualenv>=1.11.1 so that we can rely (hopefully) on a pip version which supports --pre. (tox by default uses to --pre). also merged in PR84 so that we now call "virtualenv" directly instead of looking up interpreters. Thanks Ionel Maries Cristian. + This also fixes issue140. - fix issue130: you can now set install_command=easy_install {opts} {packages} and expect it to work for repeated tox runs (previously it only worked diff -r ab3ca2815135d40e27f17c6fdfe616cbbdecd50a -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d setup.py --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ def main(): version = sys.version_info[:2] - install_requires = ['virtualenv>=1.10.1', 'py>=1.4.17', ] + install_requires = ['virtualenv>=1.11.1', 'py>=1.4.17', ] if version < (2, 7) or (3, 0) <= version <= (3, 1): install_requires += ['argparse'] if version < (2,6): @@ -28,7 +28,7 @@ description='virtualenv-based automation of test activities', long_description=open("README.rst").read(), url='http://tox.testrun.org/', - version='1.7.0.dev1', + version='1.7.0.dev2', license='http://opensource.org/licenses/MIT', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', diff -r ab3ca2815135d40e27f17c6fdfe616cbbdecd50a -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d tox.ini --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,11 @@ commands=py.test --junitxml={envlogdir}/junit-{envname}.xml {posargs} deps=pytest>=2.3.5 +[testenv:x] +setenv= + HELLO=echo hello world +commands={env:HELLO} + [testenv:docs] basepython=python changedir=doc diff -r ab3ca2815135d40e27f17c6fdfe616cbbdecd50a -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d tox/__init__.py --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '1.7.0.dev1' +__version__ = '1.7.0.dev2' class exception: class Error(Exception): diff -r ab3ca2815135d40e27f17c6fdfe616cbbdecd50a -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -268,8 +268,6 @@ extraenv=None): argv = self.envconfig.install_command[:] # use pip-script on win32 to avoid the executable locking - if argv[0] == "pip" and sys.platform == "win32": - argv[0] = "pip-script.py" i = argv.index('{packages}') argv[i:i+1] = packages if '{opts}' in argv: Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 09:35:15 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 08:35:15 -0000 Subject: [Pytest-commit] commit/pytest: bubenkoff: close wrong head Message-ID: <20140123083515.17923.89692@app08.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/81e38652d0d3/ Changeset: 81e38652d0d3 User: bubenkoff Date: 2014-01-23 09:34:56 Summary: close wrong head Affected #: 0 files Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Thu Jan 23 09:48:37 2014 From: notifications at travis-ci.org (Travis CI) Date: Thu, 23 Jan 2014 08:48:37 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#82 (master - f2f7d21) Message-ID: <52e0d764e2518_22a12173770@e833daaa-b43d-420e-9650-033dd9a878f9.mail> Build Update for hpk42/pytest ------------------------------------- Build: #82 Status: Still Failing Duration: 40 seconds Commit: f2f7d21 (master) Author: Anatoly Bubenkov Message: add Piotr Banaszkiewicz View the changeset: https://github.com/hpk42/pytest/compare/9ed6ac11b971...f2f7d2130e50 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/17464442 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Thu Jan 23 10:21:15 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 09:21:15 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: rename, refine and link to new contributing doc from several places. Message-ID: <20140123092115.27623.12550@app11.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/1811cb137050/ Changeset: 1811cb137050 User: hpk42 Date: 2014-01-23 10:21:06 Summary: rename, refine and link to new contributing doc from several places. Affected #: 7 files diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r 1811cb1370500ed9cd3a5ee6f2ebc773ad3fa6f9 CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -15,14 +15,14 @@ Do you like py.test? Share some love on Twitter or in your blog posts! We'd also like to hear about your propositions and suggestions. Feel free to -submit them as issues `here `__ and: +`submit them as issues `__ and: * Set the "kind" to "enhancement" or "proposal" so that we can quickly find about them. * Explain in detail how they should work. * Keep the scope as narrow as possible. This will make it easier to implement. -* If you have required skills and/or knowledge, you can always contribute to - these issues! +* If you have required skills and/or knowledge, we are very happy for + pull requests (see below). Report bugs ----------- diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r 1811cb1370500ed9cd3a5ee6f2ebc773ad3fa6f9 doc/en/_templates/links.html --- a/doc/en/_templates/links.html +++ b/doc/en/_templates/links.html @@ -1,6 +1,7 @@

Useful Links

  • The pytest Website
  • +
  • Contribution Guide
  • pytest @ PyPI
  • pytest @ Bitbucket
  • pytest @ github
  • diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r 1811cb1370500ed9cd3a5ee6f2ebc773ad3fa6f9 doc/en/contact.txt --- a/doc/en/contact.txt +++ b/doc/en/contact.txt @@ -18,6 +18,9 @@ - `pytest-commit at python.org (mailing list)`_: for commits and new issues +- :doc:`contribution guide ` for help on submitting pull + requests to bitbucket or github. + - #pylib on irc.freenode.net IRC channel for random questions. - private mail to Holger.Krekel at gmail com if you want to communicate sensitive issues diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r 1811cb1370500ed9cd3a5ee6f2ebc773ad3fa6f9 doc/en/contents.txt --- a/doc/en/contents.txt +++ b/doc/en/contents.txt @@ -16,7 +16,7 @@ plugins example/index talks - contribute + contributing funcarg_compare.txt announce/index diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r 1811cb1370500ed9cd3a5ee6f2ebc773ad3fa6f9 doc/en/contribute.txt --- a/doc/en/contribute.txt +++ /dev/null @@ -1,3 +0,0 @@ -.. _contributing: - -.. include:: ../../CONTRIBUTING.rst diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r 1811cb1370500ed9cd3a5ee6f2ebc773ad3fa6f9 doc/en/contributing.txt --- /dev/null +++ b/doc/en/contributing.txt @@ -0,0 +1,3 @@ +.. _contributing: + +.. include:: ../../CONTRIBUTING.rst diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r 1811cb1370500ed9cd3a5ee6f2ebc773ad3fa6f9 doc/en/develop.txt --- a/doc/en/develop.txt +++ /dev/null @@ -1,40 +0,0 @@ -================================================= -Feedback and contribute to pytest -================================================= - -.. toctree:: - :maxdepth: 2 - - contact.txt - -.. _checkout: - -Working from version control or a tarball -================================================= - -To follow development or start experiments, checkout the -complete code and documentation source with mercurial_:: - - hg clone https://bitbucket.org/hpk42/pytest/ - -You can also go to the python package index and -download and unpack a TAR file:: - - http://pypi.python.org/pypi/pytest/ - -Activating a checkout with setuptools --------------------------------------------- - -With a working Distribute_ or setuptools_ installation you can type:: - - python setup.py develop - -in order to work inline with the tools and the lib of your checkout. - -If this command complains that it could not find the required version -of "py" then you need to use the development pypi repository:: - - python setup.py develop -i http://pypi.testrun.org - - -.. include:: links.inc Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 10:51:53 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 09:51:53 -0000 Subject: [Pytest-commit] commit/pytest: bubenkoff: add explicit branch creation note Message-ID: <20140123095153.9517.178@app04.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/0b1fb07d0f8f/ Changeset: 0b1fb07d0f8f User: bubenkoff Date: 2014-01-23 10:51:45 Summary: add explicit branch creation note Affected #: 1 file diff -r 1811cb1370500ed9cd3a5ee6f2ebc773ad3fa6f9 -r 0b1fb07d0f8fbe68e5dfe60a07ccdc689241e098 CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,4 +1,3 @@ - ============ Contributing ============ @@ -6,6 +5,7 @@ Contributions are highly welcomed and appreciated. Every little help counts, so do not hesitate! + Types of contributions ====================== @@ -125,7 +125,13 @@ $ hg commit -m" $ hg push -b . -7. Submit a pull request through the BitBucket website. +7. Submit a pull request through the BitBucket website: + + source: /pytest + branch: + + target: hpk42/pytest + branch: default .. _contribution-on-github: @@ -158,4 +164,10 @@ $ git commit -am"" $ git push origin -6. Submit a pull request through the GitHub website. +6. Submit a pull request through the GitHub website using the schema:: + + base fork: hpk42/pytest + base: master + + head fork: /pytest + compare: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 11:38:13 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 10:38:13 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: refine contributing text in several places Message-ID: <20140123103813.11057.32259@app03.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/6cfd2a33354d/ Changeset: 6cfd2a33354d User: hpk42 Date: 2014-01-23 11:38:05 Summary: refine contributing text in several places Affected #: 2 files diff -r 0b1fb07d0f8fbe68e5dfe60a07ccdc689241e098 -r 6cfd2a33354d06d2481a3860a1a41d13b0d35ca2 CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -9,6 +9,19 @@ Types of contributions ====================== +Report bugs +----------- + +Report bugs at https://bitbucket.org/hpk42/pytest/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting, + specifically Python interpreter version, + installed libraries and py.test version. +* Detailed steps to reproduce the bug. + Submit feedback for developers ------------------------------ @@ -24,18 +37,6 @@ * If you have required skills and/or knowledge, we are very happy for pull requests (see below). -Report bugs ------------ - -Report bugs at https://bitbucket.org/hpk42/pytest/issues. - -If you are reporting a bug, please include: - -* Your operating system name and version. -* Any details about your local setup that might be helpful in troubleshooting, - specifically Python interpreter version, - installed libraries and py.test version. -* Detailed steps to reproduce the bug. Fix bugs -------- @@ -65,8 +66,8 @@ * Docstrings. There's never too much of them. * Blog posts, articles and such -- they're all very appreciated. -Getting started for contributing -================================ +Preparing Pull Requests on Bitbucket +===================================== The primary development platform for py.test is BitBucket. You can find all the issues there and submit pull requests. There is, however, @@ -74,58 +75,59 @@ although it only allows for submitting pull requests. For a GitHub contribution guide look :ref:`below `. -1. Fork the py.test `repository `__ on BitBucket. +1. Fork the `pytest bitbucket repository `__. It's fine to + use ``pytest`` as your fork repository name because it will live + under your user. -2. Create a local virtualenv (http://www.virtualenv.org/en/latest/):: +.. _virtualenvactivate: + +2. Create and activate a fork-specific virtualenv + (http://www.virtualenv.org/en/latest/):: $ virtualenv pytest-venv - $ cd pytest-venv/ - $ source bin/activate + $ source pytest-venv/bin/activate .. _checkout: -3. Clone your fork locally:: +3. Clone your fork locally and create a branch:: - $ hg clone ssh://hg at bitbucket.org/your_name_here/pytest - -.. _installing-dev-pytest: - -4. Install your local copy into a virtualenv:: - - $ cd pytest/ - $ python setup.py develop - - If that last command complains about not finding the required version - of "py" then you need to use the development pypi repository:: - - $ python setup.py develop -i http://pypi.testrun.org + $ hg clone ssh://hg at bitbucket.org/YOUR_BITBUCKET_USERNAME/pytest + $ cd pytest + $ hg branch .. _testing-pytest: -5. When you're done making changes, check that all of them pass all the tests - (including PEP8 and different Python interpreter versions). First install - ``tox``:: +4. You can now edit your local working copy. To test you need to + install the "tox" tool into your virtualenv:: $ pip install tox - You also need to have Python 2.7 and 3.3 available in your system. Now - running tests is as simple as issuing this one command:: + You need to have Python 2.7 and 3.3 available in your system. Now + running tests is as simple as issuing this command:: - $ tox -e py27,py33 + $ python runtox.py -e py27,py33,flakes - This command will run tests for both Python 2.7 and 3.3, which is a minimum - required to get your patch merged. To run whole test suit issue:: + This command will run tests via the "tox" tool against Python 2.7 and 3.3 + and also perform "flakes" coding-style checks. ``runtox.py`` is + a thin wrapper around ``tox`` which installs from a development package + index where newer (not yet released to pypi) versions of dependencies + (especially ``py``) might be present. - $ tox + To run tests on py27 and pass options (e.g. enter pdb on failure) + to pytest you can do:: -6. Commit your changes and push to BitBucket:: + $ python runtox.py -e py27 -- --pdb - $ hg branch - $ hg add . - $ hg commit -m" + or to only run tests in a particular test module on py33:: + + $ python runtox.py -e py33 -- testing/test_config.py + +5. Commit and push once your tests pass and you are happy with your change(s):: + + $ hg commit -m"" $ hg push -b . -7. Submit a pull request through the BitBucket website: +6. Finally, submit a pull request through the BitBucket website:: source: /pytest branch: @@ -133,34 +135,32 @@ target: hpk42/pytest branch: default +.. _contribution-on-github: -.. _contribution-on-github: -What about GitHub? ------------------- +Preparing Pull Requests on Github +===================================== .. warning:: + Remember that GitHub is **not** a default development platform for py.test and it doesn't include e.g. issue list. -1. Fork the py.test `repository `__ on GitHub. +1. Fork the `pytest github repository `__. -2. Create a local virtualenv (http://www.virtualenv.org/en/latest/):: +2. :ref:`create and activate virtualenv `. - $ virtualenv pytest-venv - $ cd pytest-venv/ +3. Clone your github fork locally and create a branch:: -3. Clone your fork locally:: + $ git clone git at github.com:YOUR_GITHUB_USERNAME/pytest.git + $ cd pytest + $ git branch + $ git checkout - $ git clone git at github.com:your_name_here/pytest.git - -4. :ref:`Install your local copy into a virtualenv ` - and after that :ref:`test your changes `. +4. :ref:`test your changes `. 5. Commit your changes and push to GitHub:: - $ git branch - $ git checkout - $ git add . + $ git add PATH/TO/MODIFIED/FILE # to add changes to staging $ git commit -am"" $ git push origin diff -r 0b1fb07d0f8fbe68e5dfe60a07ccdc689241e098 -r 6cfd2a33354d06d2481a3860a1a41d13b0d35ca2 runtox.py --- /dev/null +++ b/runtox.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import subprocess +import sys + +if __name__ == "__main__": + subprocess.call(["tox", + "-i", "ALL=https://devpi.net/hpk/dev/", + "--develop",] + sys.argv[1:]) + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 11:42:26 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 10:42:26 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: speak about "pytest" rather than "py.test". Thanks Jurko. Message-ID: <20140123104226.31484.153@app04.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/b96fa77ac4af/ Changeset: b96fa77ac4af User: hpk42 Date: 2014-01-23 11:42:20 Summary: speak about "pytest" rather than "py.test". Thanks Jurko. Affected #: 1 file diff -r 6cfd2a33354d06d2481a3860a1a41d13b0d35ca2 -r b96fa77ac4af935a5a7b967ab11ece8bb02e6012 CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -19,13 +19,13 @@ * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting, specifically Python interpreter version, - installed libraries and py.test version. + installed libraries and pytest version. * Detailed steps to reproduce the bug. Submit feedback for developers ------------------------------ -Do you like py.test? Share some love on Twitter or in your blog posts! +Do you like pytest? Share some love on Twitter or in your blog posts! We'd also like to hear about your propositions and suggestions. Feel free to `submit them as issues `__ and: @@ -59,7 +59,7 @@ Write documentation ------------------- -py.test could always use more documentation. What exactly is needed? +pytest could always use more documentation. What exactly is needed? * More complementary documentation. Have you perhaps found something unclear? * Documentation translations. We currently have English and Japanese versions. @@ -69,7 +69,7 @@ Preparing Pull Requests on Bitbucket ===================================== -The primary development platform for py.test is BitBucket. You can find all +The primary development platform for pytest is BitBucket. You can find all the issues there and submit pull requests. There is, however, a `GitHub mirror `__ available, too, although it only allows for submitting pull requests. For a GitHub @@ -142,7 +142,7 @@ .. warning:: - Remember that GitHub is **not** a default development platform for py.test + Remember that GitHub is **not** a default development platform for pytest and it doesn't include e.g. issue list. 1. Fork the `pytest github repository `__. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 11:42:55 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 10:42:55 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20140123104255.1832.29233@app10.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/2e18fb60a375/ Changeset: 2e18fb60a375 Branch: document_ExceptionInfo_ref_cycle User: jurko Date: 2014-01-23 09:46:36 Summary: document explicitly clearing local references to pytest.raises() results pytest.raises() returns an ExceptionInfo object which, if a local reference is made to it, forms a reference cycle: ExceptionInfo --> exception --> stack frame raising the exception --> current stack frame --> current local variables --> Exception Info Such a reference cycle would then prevent any local variables in the current stack frame, or any of its child stack frames involved in the same reference cycle, from being garbage collected until the next reference cycle garbage collection phase. This unnecessarily increases the program's memory footprint and potentially slows it down. This situation is based on a similar one described in the official 'try' statement Python documentation for locally stored exception references. Affected #: 1 file diff -r 60052491d38bf3fd68909c35aa04e063415fe2b6 -r 2e18fb60a37595729a4ec9fbed78091f84a2cf20 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -938,6 +938,12 @@ This helper produces a ``py.code.ExceptionInfo()`` object. + Note that any local references made to such returned + ``py.code.ExceptionInfo()`` objects should be explicitly cleared, as they + are part of a reference cycle similar to local references to caught Python + exception objects. See the official Python ``try`` statement documentation + for more detailed information. + If using Python 2.5 or above, you may use this function as a context manager:: https://bitbucket.org/hpk42/pytest/commits/89e8707d6b2f/ Changeset: 89e8707d6b2f Branch: document_ExceptionInfo_ref_cycle User: jurko Date: 2014-01-23 11:36:04 Summary: reword note on explicitly clearing local references to pytest.raises() results Made it clearer that clearing such references is not mandatory and is only an optional step which may help the Python interpreter speed up its garbage collection. Affected #: 1 file diff -r 2e18fb60a37595729a4ec9fbed78091f84a2cf20 -r 89e8707d6b2f45a79331f5865a2a42bf11f681d3 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -938,12 +938,6 @@ This helper produces a ``py.code.ExceptionInfo()`` object. - Note that any local references made to such returned - ``py.code.ExceptionInfo()`` objects should be explicitly cleared, as they - are part of a reference cycle similar to local references to caught Python - exception objects. See the official Python ``try`` statement documentation - for more detailed information. - If using Python 2.5 or above, you may use this function as a context manager:: @@ -968,6 +962,22 @@ >>> raises(ZeroDivisionError, "f(0)") + + Performance note: + ----------------- + + Similar to caught exception objects in Python, explicitly clearing local + references to returned ``py.code.ExceptionInfo`` objects can help the Python + interpreter speed up its garbage collection. + + Clearing those references breaks a reference cycle (``ExceptionInfo`` --> + caught exception --> frame stack raising the exception --> current frame + stack --> local variables --> ``ExceptionInfo``) which makes Python keep all + objects referenced from that cycle (including all local variables in the + current frame) alive until the next cyclic garbage collection run. See the + official Python ``try`` statement documentation for more detailed + information. + """ __tracebackhide__ = True if ExpectedException is AssertionError: https://bitbucket.org/hpk42/pytest/commits/7432b6d6f51d/ Changeset: 7432b6d6f51d User: hpk42 Date: 2014-01-23 11:42:51 Summary: Merged in jurko/pytest/document_ExceptionInfo_ref_cycle (pull request #109) document explicitly clearing local references to pytest.raises() results (redo of pull request #98) Affected #: 1 file diff -r b96fa77ac4af935a5a7b967ab11ece8bb02e6012 -r 7432b6d6f51d935054290c8020d211eb07af485e _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -962,6 +962,22 @@ >>> raises(ZeroDivisionError, "f(0)") + + Performance note: + ----------------- + + Similar to caught exception objects in Python, explicitly clearing local + references to returned ``py.code.ExceptionInfo`` objects can help the Python + interpreter speed up its garbage collection. + + Clearing those references breaks a reference cycle (``ExceptionInfo`` --> + caught exception --> frame stack raising the exception --> current frame + stack --> local variables --> ``ExceptionInfo``) which makes Python keep all + objects referenced from that cycle (including all local variables in the + current frame) alive until the next cyclic garbage collection run. See the + official Python ``try`` statement documentation for more detailed + information. + """ __tracebackhide__ = True if ExpectedException is AssertionError: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 12:12:04 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 11:12:04 -0000 Subject: [Pytest-commit] commit/py: hpk42: document ExceptionInfo members Message-ID: <20140123111204.27635.20126@app08.ash-private.bitbucket.org> 1 new commit in py: https://bitbucket.org/hpk42/py/commits/b4230dbdd9b5/ Changeset: b4230dbdd9b5 User: hpk42 Date: 2014-01-23 12:11:57 Summary: document ExceptionInfo members Affected #: 2 files diff -r 13d9af95547ea14b2e33e2994ff96e182da225c4 -r b4230dbdd9b5127a320fd1caa9861ca1577e0d98 doc/code.txt --- a/doc/code.txt +++ b/doc/code.txt @@ -145,3 +145,6 @@ .. autoclass:: py.code.ExceptionInfo :members: +.. autoclass:: py.code.Traceback + :members: + diff -r 13d9af95547ea14b2e33e2994ff96e182da225c4 -r b4230dbdd9b5127a320fd1caa9861ca1577e0d98 py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -347,9 +347,16 @@ if exprinfo and exprinfo.startswith('assert '): self._striptext = 'AssertionError: ' self._excinfo = tup - self.type, self.value, tb = tup + #: the exception class + self.type = tup[0] + #: the exception instance + self.value = tup[1] + #: the exception raw traceback + self.tb = tup[2] + #: the exception type name self.typename = self.type.__name__ - self.traceback = py.code.Traceback(tb) + #: the exception traceback (py.code.Traceback instance) + self.traceback = py.code.Traceback(self.tb) def __repr__(self): return "" % (self.typename, len(self.traceback)) Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 12:16:56 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 11:16:56 -0000 Subject: [Pytest-commit] commit/py: hpk42: remove comment about ExceptionInfo attributes being private. Message-ID: <20140123111656.25517.79298@app12.ash-private.bitbucket.org> 1 new commit in py: https://bitbucket.org/hpk42/py/commits/472806557434/ Changeset: 472806557434 User: hpk42 Date: 2014-01-23 12:16:49 Summary: remove comment about ExceptionInfo attributes being private. Affected #: 1 file diff -r b4230dbdd9b5127a320fd1caa9861ca1577e0d98 -r 47280655743431abd4355062ae1db788790c582e py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -336,8 +336,6 @@ """ _striptext = '' def __init__(self, tup=None, exprinfo=None): - # NB. all attributes are private! Subclasses or other - # ExceptionInfo-like classes may have different attributes. if tup is None: tup = sys.exc_info() if exprinfo is None and isinstance(tup[1], AssertionError): Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 12:18:29 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 11:18:29 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: have travis use the devpi index to get the pylib dependency Message-ID: <20140123111829.19583.91261@app04.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/25ce164b8357/ Changeset: 25ce164b8357 User: hpk42 Date: 2014-01-23 12:18:20 Summary: have travis use the devpi index to get the pylib dependency Affected #: 1 file diff -r 7432b6d6f51d935054290c8020d211eb07af485e -r 25ce164b8357ea41373f93874ab5c5b7320f16a5 .travis.yml --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,8 @@ # command to install dependencies install: "pip install -U detox" # # command to run tests -script: detox --recreate +script: detox --recreate -i ALL=https://devpi.net/hpk/dev/ + notifications: irc: - "chat.freenode.net#pytest-dev" Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 13:07:36 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 12:07:36 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: add Daniel Greensfeld 3-part blog series about pytest Message-ID: <20140123120736.6280.58754@app18.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/6d7859aa371f/ Changeset: 6d7859aa371f User: hpk42 Date: 2014-01-23 13:07:28 Summary: add Daniel Greensfeld 3-part blog series about pytest Affected #: 1 file diff -r 25ce164b8357ea41373f93874ab5c5b7320f16a5 -r 6d7859aa371f9ad5f9a7f2ab1b619fc801ffeddf doc/en/talks.txt --- a/doc/en/talks.txt +++ b/doc/en/talks.txt @@ -18,6 +18,9 @@ - `pytest introduction from Brian Okken (January 2013) `_ +- `3-part blog series about pytest from Daniel Greenfeld (January + 2014) `_ + - `pycon australia 2012 pytest talk from Brianna Laugher `_ (`video `_, `slides `_, `code `_) - `pycon 2012 US talk video from Holger Krekel `_ Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 13:22:22 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 12:22:22 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140123122222.4247.17765@app01.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/cf98811772af/ Changeset: cf98811772af User: bubenkoff Date: 2014-01-23 13:19:49 Summary: remove the github contribution section Affected #: 1 file diff -r 0b1fb07d0f8fbe68e5dfe60a07ccdc689241e098 -r cf98811772af71b4ae1337a7990e1e36a6d7b3fb CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -134,40 +134,18 @@ branch: default -.. _contribution-on-github: -What about GitHub? ------------------- +.. _contribution-using-git: +What about git (and so GitHub)? +------------------------------- + +There used to be the pytest github mirror. It was removed in favor of this mercurial one, to remove confusion of people +not knowing where it's better to put their issues and pull requests. Also it wasn't easilily possible to automate +mirroring process. +However, it's still possible to use git to contribute to pytest using tools like https://github.com/buchuki/gitifyhg +which allow you to clone and work mercurial repo still using git. .. warning:: - Remember that GitHub is **not** a default development platform for py.test - and it doesn't include e.g. issue list. + Remember that git is **not** a default version control system py.test and you need to be careful using git + to work with it. -1. Fork the py.test `repository `__ on GitHub. - -2. Create a local virtualenv (http://www.virtualenv.org/en/latest/):: - - $ virtualenv pytest-venv - $ cd pytest-venv/ - -3. Clone your fork locally:: - - $ git clone git at github.com:your_name_here/pytest.git - -4. :ref:`Install your local copy into a virtualenv ` - and after that :ref:`test your changes `. - -5. Commit your changes and push to GitHub:: - - $ git branch - $ git checkout - $ git add . - $ git commit -am"" - $ git push origin - -6. Submit a pull request through the GitHub website using the schema:: - - base fork: hpk42/pytest - base: master - - head fork: /pytest - compare: +Please read the manual carefully, and then use same contribution manual as for BitBucket. https://bitbucket.org/hpk42/pytest/commits/4e5babc67814/ Changeset: 4e5babc67814 User: bubenkoff Date: 2014-01-23 13:21:00 Summary: merge with mainline Affected #: 5 files diff -r cf98811772af71b4ae1337a7990e1e36a6d7b3fb -r 4e5babc678148d09b323969a39c6515503b6e5b8 .travis.yml --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,8 @@ # command to install dependencies install: "pip install -U detox" # # command to run tests -script: detox --recreate +script: detox --recreate -i ALL=https://devpi.net/hpk/dev/ + notifications: irc: - "chat.freenode.net#pytest-dev" diff -r cf98811772af71b4ae1337a7990e1e36a6d7b3fb -r 4e5babc678148d09b323969a39c6515503b6e5b8 CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -9,10 +9,23 @@ Types of contributions ====================== +Report bugs +----------- + +Report bugs at https://bitbucket.org/hpk42/pytest/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting, + specifically Python interpreter version, + installed libraries and pytest version. +* Detailed steps to reproduce the bug. + Submit feedback for developers ------------------------------ -Do you like py.test? Share some love on Twitter or in your blog posts! +Do you like pytest? Share some love on Twitter or in your blog posts! We'd also like to hear about your propositions and suggestions. Feel free to `submit them as issues `__ and: @@ -24,18 +37,6 @@ * If you have required skills and/or knowledge, we are very happy for pull requests (see below). -Report bugs ------------ - -Report bugs at https://bitbucket.org/hpk42/pytest/issues. - -If you are reporting a bug, please include: - -* Your operating system name and version. -* Any details about your local setup that might be helpful in troubleshooting, - specifically Python interpreter version, - installed libraries and py.test version. -* Detailed steps to reproduce the bug. Fix bugs -------- @@ -58,74 +59,75 @@ Write documentation ------------------- -py.test could always use more documentation. What exactly is needed? +pytest could always use more documentation. What exactly is needed? * More complementary documentation. Have you perhaps found something unclear? * Documentation translations. We currently have English and Japanese versions. * Docstrings. There's never too much of them. * Blog posts, articles and such -- they're all very appreciated. -Getting started for contributing -================================ +Preparing Pull Requests on Bitbucket +===================================== -The primary development platform for py.test is BitBucket. You can find all +The primary development platform for pytest is BitBucket. You can find all the issues there and submit pull requests. There is, however, a `GitHub mirror `__ available, too, although it only allows for submitting pull requests. For a GitHub contribution guide look :ref:`below `. -1. Fork the py.test `repository `__ on BitBucket. +1. Fork the `pytest bitbucket repository `__. It's fine to + use ``pytest`` as your fork repository name because it will live + under your user. -2. Create a local virtualenv (http://www.virtualenv.org/en/latest/):: +.. _virtualenvactivate: + +2. Create and activate a fork-specific virtualenv + (http://www.virtualenv.org/en/latest/):: $ virtualenv pytest-venv - $ cd pytest-venv/ - $ source bin/activate + $ source pytest-venv/bin/activate .. _checkout: -3. Clone your fork locally:: +3. Clone your fork locally and create a branch:: - $ hg clone ssh://hg at bitbucket.org/your_name_here/pytest - -.. _installing-dev-pytest: - -4. Install your local copy into a virtualenv:: - - $ cd pytest/ - $ python setup.py develop - - If that last command complains about not finding the required version - of "py" then you need to use the development pypi repository:: - - $ python setup.py develop -i http://pypi.testrun.org + $ hg clone ssh://hg at bitbucket.org/YOUR_BITBUCKET_USERNAME/pytest + $ cd pytest + $ hg branch .. _testing-pytest: -5. When you're done making changes, check that all of them pass all the tests - (including PEP8 and different Python interpreter versions). First install - ``tox``:: +4. You can now edit your local working copy. To test you need to + install the "tox" tool into your virtualenv:: $ pip install tox - You also need to have Python 2.7 and 3.3 available in your system. Now - running tests is as simple as issuing this one command:: + You need to have Python 2.7 and 3.3 available in your system. Now + running tests is as simple as issuing this command:: - $ tox -e py27,py33 + $ python runtox.py -e py27,py33,flakes - This command will run tests for both Python 2.7 and 3.3, which is a minimum - required to get your patch merged. To run whole test suit issue:: + This command will run tests via the "tox" tool against Python 2.7 and 3.3 + and also perform "flakes" coding-style checks. ``runtox.py`` is + a thin wrapper around ``tox`` which installs from a development package + index where newer (not yet released to pypi) versions of dependencies + (especially ``py``) might be present. - $ tox + To run tests on py27 and pass options (e.g. enter pdb on failure) + to pytest you can do:: -6. Commit your changes and push to BitBucket:: + $ python runtox.py -e py27 -- --pdb - $ hg branch - $ hg add . - $ hg commit -m" + or to only run tests in a particular test module on py33:: + + $ python runtox.py -e py33 -- testing/test_config.py + +5. Commit and push once your tests pass and you are happy with your change(s):: + + $ hg commit -m"" $ hg push -b . -7. Submit a pull request through the BitBucket website: +6. Finally, submit a pull request through the BitBucket website:: source: /pytest branch: diff -r cf98811772af71b4ae1337a7990e1e36a6d7b3fb -r 4e5babc678148d09b323969a39c6515503b6e5b8 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -962,6 +962,22 @@ >>> raises(ZeroDivisionError, "f(0)") + + Performance note: + ----------------- + + Similar to caught exception objects in Python, explicitly clearing local + references to returned ``py.code.ExceptionInfo`` objects can help the Python + interpreter speed up its garbage collection. + + Clearing those references breaks a reference cycle (``ExceptionInfo`` --> + caught exception --> frame stack raising the exception --> current frame + stack --> local variables --> ``ExceptionInfo``) which makes Python keep all + objects referenced from that cycle (including all local variables in the + current frame) alive until the next cyclic garbage collection run. See the + official Python ``try`` statement documentation for more detailed + information. + """ __tracebackhide__ = True if ExpectedException is AssertionError: diff -r cf98811772af71b4ae1337a7990e1e36a6d7b3fb -r 4e5babc678148d09b323969a39c6515503b6e5b8 doc/en/talks.txt --- a/doc/en/talks.txt +++ b/doc/en/talks.txt @@ -18,6 +18,9 @@ - `pytest introduction from Brian Okken (January 2013) `_ +- `3-part blog series about pytest from Daniel Greenfeld (January + 2014) `_ + - `pycon australia 2012 pytest talk from Brianna Laugher `_ (`video `_, `slides `_, `code `_) - `pycon 2012 US talk video from Holger Krekel `_ diff -r cf98811772af71b4ae1337a7990e1e36a6d7b3fb -r 4e5babc678148d09b323969a39c6515503b6e5b8 runtox.py --- /dev/null +++ b/runtox.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import subprocess +import sys + +if __name__ == "__main__": + subprocess.call(["tox", + "-i", "ALL=https://devpi.net/hpk/dev/", + "--develop",] + sys.argv[1:]) + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 14:51:06 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 13:51:06 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: remove github links Message-ID: <20140123135106.1816.19176@app09.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/0a7e3072aed6/ Changeset: 0a7e3072aed6 User: hpk42 Date: 2014-01-23 14:50:58 Summary: remove github links Affected #: 3 files diff -r 4e5babc678148d09b323969a39c6515503b6e5b8 -r 0a7e3072aed639c436b47a60e364c30875976111 doc/en/_templates/links.html --- a/doc/en/_templates/links.html +++ b/doc/en/_templates/links.html @@ -4,7 +4,6 @@
  • Contribution Guide
  • pytest @ PyPI
  • pytest @ Bitbucket
  • -
  • pytest @ github
  • Issue Tracker
  • PDF Documentation
diff -r 4e5babc678148d09b323969a39c6515503b6e5b8 -r 0a7e3072aed639c436b47a60e364c30875976111 doc/en/contact.txt --- a/doc/en/contact.txt +++ b/doc/en/contact.txt @@ -19,7 +19,7 @@ - `pytest-commit at python.org (mailing list)`_: for commits and new issues - :doc:`contribution guide ` for help on submitting pull - requests to bitbucket or github. + requests to bitbucket (including using git via gitifyhg). - #pylib on irc.freenode.net IRC channel for random questions. diff -r 4e5babc678148d09b323969a39c6515503b6e5b8 -r 0a7e3072aed639c436b47a60e364c30875976111 doc/en/status.txt --- a/doc/en/status.txt +++ b/doc/en/status.txt @@ -1,8 +1,5 @@ pytest development status ================================ -github triggered travis: +https://drone.io/bitbucket.org/hpk42/pytest -.. image:: https://secure.travis-ci.org/hpk42/pytest.png - :target: http://travis-ci.org/hpk42/pytest - Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 15:08:53 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 14:08:53 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: add Jurko to authors/contributors file Message-ID: <20140123140853.21788.1889@app12.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/4377714d60a3/ Changeset: 4377714d60a3 User: hpk42 Date: 2014-01-23 15:08:24 Summary: add Jurko to authors/contributors file Affected #: 1 file diff -r 0a7e3072aed639c436b47a60e364c30875976111 -r 4377714d60a33dece691daff4b53062ee6780a35 AUTHORS --- a/AUTHORS +++ b/AUTHORS @@ -37,3 +37,4 @@ Anthon van der Neut Mark Abramowitz Piotr Banaszkiewicz +Jurko Gospodneti? Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 23 15:25:09 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 23 Jan 2014 14:25:09 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: address issue416: clarify docs as to conftest.py loading semantics Message-ID: <20140123142509.27261.47482@app08.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/8c0e79d2c8ca/ Changeset: 8c0e79d2c8ca User: hpk42 Date: 2014-01-23 15:25:01 Summary: address issue416: clarify docs as to conftest.py loading semantics Affected #: 2 files diff -r 4377714d60a33dece691daff4b53062ee6780a35 -r 8c0e79d2c8cab40e85e94d4193c0cafcba1b78d2 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,9 @@ correctly also on python2 and with pytest-xdist runs. (the fix requires py-1.4.20) +- address issue416: clarify docs as to conftest.py loading semantics + + 2.5.1 ----------------------------------- diff -r 4377714d60a33dece691daff4b53062ee6780a35 -r 8c0e79d2c8cab40e85e94d4193c0cafcba1b78d2 doc/en/plugins.txt --- a/doc/en/plugins.txt +++ b/doc/en/plugins.txt @@ -177,9 +177,15 @@ and loading the specified plugin before actual command line parsing. * by loading all :file:`conftest.py` files as inferred by the command line - invocation (test files and all of its *parent* directories). - Note that ``conftest.py`` files from *sub* directories are by default - not loaded at tool startup. + invocation: + + - if no test paths are specified use current dir as a test path + - if exists, load ``conftest.py`` and ``test*/conftest.py`` relative + to the directory part of the first test path. + + Note that pytest does not find ``conftest.py`` files in deeper nested + sub directories at tool startup. It is usually a good idea to keep + your conftest.py file in the top level test or project root directory. * by recursively loading all plugins specified by the ``pytest_plugins`` variable in ``conftest.py`` files Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Thu Jan 23 15:36:12 2014 From: issues-reply at bitbucket.org (holger krekel) Date: Thu, 23 Jan 2014 14:36:12 -0000 Subject: [Pytest-commit] Issue #430: Config variable to set locations to try for conftest.py files (hpk42/pytest) Message-ID: <20140123143612.25219.63551@app03.ash-private.bitbucket.org> New issue 430: Config variable to set locations to try for conftest.py files https://bitbucket.org/hpk42/pytest/issue/430/config-variable-to-set-locations-to-try holger krekel: Discussed with @jurko and others: It would be good to have a ``conftestscan`` ini variable which you can set in order to have pytest scan for conftest files. Examples: - ``conftestscan = test*/conftest.py`` (the default) would make pytest look for a ``conftest.py`` in any sub directory of the directory containing the ini-file. - ``conftestscan = test*/**/conftest.py`` would make pytest do a recursive search in all subdirs. - ``conftestscan = myproj/**/conftest.py`` would make pytest scan all subdirs in the project/package directory for ``conftest.py`` files. Note that the only effect of ``conftestscan`` is to load conftest files early and make e.g. its command line options available. Any fixture functions or e.g. ``pytest_runtest_*`` hooks would still only be available to all the tests under the directory of the respective ``conftest.py`` file where they are defined. In other words, ``conftestscan`` does not turn ``conftest.py`` into global plugins. From issues-reply at bitbucket.org Thu Jan 23 23:21:21 2014 From: issues-reply at bitbucket.org (Ronny Pfannschmidt) Date: Thu, 23 Jan 2014 22:21:21 -0000 Subject: [Pytest-commit] Issue #431: opt-in to store the last n sets of reports (hpk42/pytest) Message-ID: <20140123222121.540.85880@app10.ash-private.bitbucket.org> New issue 431: opt-in to store the last n sets of reports https://bitbucket.org/hpk42/pytest/issue/431/opt-in-to-store-the-last-n-sets-of-reports Ronny Pfannschmidt: i'd like to propose a way to store all last reports in a numbered file in the cache directory the mode of operation should be the following -> open in append mode (also on slaves) -> for each report write the serialized string of that report to the file this would allow to compare test runs, create reports after a test, and help with analysis for crashes in tests its also free of the problems of something like a incremental junitxml and as additional we'd require serializable forms of the test reports in core, removing that from xdist and makign it more flexible From issues-reply at bitbucket.org Fri Jan 24 20:52:43 2014 From: issues-reply at bitbucket.org (Piotr Banaszkiewicz) Date: Fri, 24 Jan 2014 19:52:43 -0000 Subject: [Pytest-commit] Issue #432: Testing docs and doc tests (hpk42/pytest) Message-ID: <20140124195243.3710.45034@app06.ash-private.bitbucket.org> New issue 432: Testing docs and doc tests https://bitbucket.org/hpk42/pytest/issue/432/testing-docs-and-doc-tests Piotr Banaszkiewicz: Testing docs with tox right now requires `make`. Not everyone has it installed. (And `regen` target for tox doesn't work, too) I propose to expand testing docs and doctests so that: 1. rst syntax in docstrings is checked 2. `make` is no longed needed 3. doc trees are shared per tox env. run 4. `rm -rf` is not needed ([lets not repeat other projects' mistakes](https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/commit/a047be85247755cdbe0acce6f1dafc8beb84f2ac#diff-3fbb47e318cd8802bd325e7da9aaabe8L351)) 5. Sphinx is more strict about warnings (`-W`) I'm ready to submit a pull request if you agree. I would also like to somehow force developers to write docs about implemented new features or changed pytest behavior. From commits-noreply at bitbucket.org Fri Jan 24 20:56:45 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 24 Jan 2014 19:56:45 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20140124195645.3712.61785@app06.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/a4999cc9837a/ Changeset: a4999cc9837a User: pbanaszkiewicz Date: 2014-01-24 19:21:21 Summary: Contribution guide: added "what is pull request" section Affected #: 1 file diff -r 8c0e79d2c8cab40e85e94d4193c0cafcba1b78d2 -r a4999cc9837abdda131ccdb5f3a8396031fa9c6b CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -35,7 +35,7 @@ * Explain in detail how they should work. * Keep the scope as narrow as possible. This will make it easier to implement. * If you have required skills and/or knowledge, we are very happy for - pull requests (see below). + :ref:`pull requests `. Fix bugs @@ -66,14 +66,23 @@ * Docstrings. There's never too much of them. * Blog posts, articles and such -- they're all very appreciated. +.. _pull-requests: + Preparing Pull Requests on Bitbucket ===================================== +.. note:: + What is a "pull request"? It informs project's core developers about the + changes you want to review and merge. Pull requests are stored on + `BitBucket servers `__. + Once you send pull request, we can discuss it's potential modifications and + even add more commits to it later on. + The primary development platform for pytest is BitBucket. You can find all the issues there and submit pull requests. There is, however, a `GitHub mirror `__ available, too, although it only allows for submitting pull requests. For a GitHub -contribution guide look :ref:`below `. +contribution guide look :ref:`below `. 1. Fork the `pytest bitbucket repository `__. It's fine to use ``pytest`` as your fork repository name because it will live https://bitbucket.org/hpk42/pytest/commits/9859b18ee4f0/ Changeset: 9859b18ee4f0 User: pbanaszkiewicz Date: 2014-01-24 19:37:44 Summary: Contribution guide: removed confusion regarding git Affected #: 1 file diff -r a4999cc9837abdda131ccdb5f3a8396031fa9c6b -r 9859b18ee4f095507af27eaf5accdb65b1694fdd CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -79,14 +79,12 @@ even add more commits to it later on. The primary development platform for pytest is BitBucket. You can find all -the issues there and submit pull requests. There is, however, -a `GitHub mirror `__ available, too, -although it only allows for submitting pull requests. For a GitHub -contribution guide look :ref:`below `. +the issues there and submit your pull requests. -1. Fork the `pytest bitbucket repository `__. It's fine to - use ``pytest`` as your fork repository name because it will live - under your user. +1. Fork the + `pytest BitBucket repository `__. It's + fine to use ``pytest`` as your fork repository name because it will live + under your user. .. _virtualenvactivate: @@ -98,11 +96,15 @@ .. _checkout: -3. Clone your fork locally and create a branch:: +3. Clone your fork locally using `Mercurial `_ + (``hg``) and create a branch:: $ hg clone ssh://hg at bitbucket.org/YOUR_BITBUCKET_USERNAME/pytest $ cd pytest - $ hg branch + $ hg branch your-branch-name + + If you need some help with Mercurial, follow this quick start + guide: http://mercurial.selenic.com/wiki/QuickStart .. _testing-pytest: @@ -138,8 +140,8 @@ 6. Finally, submit a pull request through the BitBucket website:: - source: /pytest - branch: + source: YOUR_BITBUCKET_USERNAME/pytest + branch: your-branch-name target: hpk42/pytest branch: default @@ -149,14 +151,18 @@ What about git (and so GitHub)? ------------------------------- -There used to be the pytest github mirror. It was removed in favor of this mercurial one, to remove confusion of people -not knowing where it's better to put their issues and pull requests. Also it wasn't easilily possible to automate -mirroring process. -However, it's still possible to use git to contribute to pytest using tools like https://github.com/buchuki/gitifyhg -which allow you to clone and work mercurial repo still using git. +There used to be the pytest GitHub mirror. It was removed in favor of the +Mercurial one, to remove confusion of people not knowing where it's better to +put their issues and pull requests. Also it wasn't easily possible to automate +the mirroring process. + +However, it's still possible to use git to contribute to pytest using tools +like `gitifyhg `_ which allows you to +clone and work with Mercurial repo still using git. .. warning:: - Remember that git is **not** a default version control system py.test and you need to be careful using git - to work with it. + Remember that git is **not** a default version control system for pytest and + you need to be careful using it. -Please read the manual carefully, and then use same contribution manual as for BitBucket. +Please read the manual carefully, and then use same contribution manual as for +BitBucket. https://bitbucket.org/hpk42/pytest/commits/f428ddd78673/ Changeset: f428ddd78673 User: pbanaszkiewicz Date: 2014-01-24 20:01:04 Summary: Contribution guide: added pull request button image Affected #: 2 files diff -r 9859b18ee4f095507af27eaf5accdb65b1694fdd -r f428ddd78673080a63c59887cb4f603d29d6ed4a CONTRIBUTING.rst --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -138,7 +138,13 @@ $ hg commit -m"" $ hg push -b . -6. Finally, submit a pull request through the BitBucket website:: +6. Finally, submit a pull request through the BitBucket website: + + .. image:: img/pullrequest.png + :width: 700px + :align: center + + :: source: YOUR_BITBUCKET_USERNAME/pytest branch: your-branch-name @@ -146,8 +152,8 @@ target: hpk42/pytest branch: default +.. _contribution-using-git: -.. _contribution-using-git: What about git (and so GitHub)? ------------------------------- @@ -163,6 +169,3 @@ .. warning:: Remember that git is **not** a default version control system for pytest and you need to be careful using it. - -Please read the manual carefully, and then use same contribution manual as for -BitBucket. diff -r 9859b18ee4f095507af27eaf5accdb65b1694fdd -r f428ddd78673080a63c59887cb4f603d29d6ed4a doc/en/img/pullrequest.png Binary file doc/en/img/pullrequest.png has changed Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Jan 24 21:46:08 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 24 Jan 2014 20:46:08 -0000 Subject: [Pytest-commit] commit/pytest: RonnyPfannschmidt: Redo the Capture integration propperly Message-ID: <20140124204608.16594.65089@app04.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/552a700dc71f/ Changeset: 552a700dc71f User: RonnyPfannschmidt Date: 2014-01-24 21:22:19 Summary: Redo the Capture integration propperly Affected #: 3 files diff -r f428ddd78673080a63c59887cb4f603d29d6ed4a -r 552a700dc71f69bc5b28970ec2ff500fbaea77cb CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -15,9 +15,15 @@ correctly also on python2 and with pytest-xdist runs. (the fix requires py-1.4.20) +- copy, cleanup and integrate py.io capture + from pylib 1.4.20.dev2 (rev 13d9af95547e) + - address issue416: clarify docs as to conftest.py loading semantics +- make capfd/capsys.capture private, its unused and shouldnt be exposed + + 2.5.1 ----------------------------------- diff -r f428ddd78673080a63c59887cb4f603d29d6ed4a -r 552a700dc71f69bc5b28970ec2ff500fbaea77cb _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -1,17 +1,55 @@ -""" per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments. """ - -import pytest, py +""" + per-test stdout/stderr capturing mechanisms, + ``capsys`` and ``capfd`` function arguments. +""" +# note: py.io capture was where copied from +# pylib 1.4.20.dev2 (rev 13d9af95547e) import sys import os +import tempfile + +import py +import pytest + +try: + from io import StringIO +except ImportError: + from StringIO import StringIO + +try: + from io import BytesIO +except ImportError: + class BytesIO(StringIO): + def write(self, data): + if isinstance(data, unicode): + raise TypeError("not a byte value: %r" % (data,)) + StringIO.write(self, data) + +if sys.version_info < (3, 0): + class TextIO(StringIO): + def write(self, data): + if not isinstance(data, unicode): + enc = getattr(self, '_encoding', 'UTF-8') + data = unicode(data, enc, 'replace') + StringIO.write(self, data) +else: + TextIO = StringIO + + +patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} + def pytest_addoption(parser): group = parser.getgroup("general") - group._addoption('--capture', action="store", default=None, + group._addoption( + '--capture', action="store", default=None, metavar="method", 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.") + @pytest.mark.tryfirst def pytest_load_initial_conftests(early_config, parser, args, __multicall__): ns = parser.parse_known_args(args) @@ -22,13 +60,16 @@ method = "sys" capman = CaptureManager(method) early_config.pluginmanager.register(capman, "capturemanager") + # make sure that capturemanager is properly reset at final shutdown def teardown(): try: capman.reset_capturings() except ValueError: pass + early_config.pluginmanager.add_shutdown(teardown) + # make sure logging does not raise exceptions at the end def silence_logging_at_shutdown(): if "logging" in sys.modules: @@ -47,21 +88,27 @@ sys.stderr.write(err) raise + def addouterr(rep, outerr): for secname, content in zip(["out", "err"], outerr): if content: rep.sections.append(("Captured std%s" % secname, content)) + class NoCapture: def startall(self): pass + def resume(self): pass + def reset(self): pass + def suspend(self): return "", "" + class CaptureManager: def __init__(self, defaultmethod=None): self._method2capture = {} @@ -69,21 +116,25 @@ def _maketempfile(self): f = py.std.tempfile.TemporaryFile() - newf = py.io.dupfile(f, encoding="UTF-8") + newf = dupfile(f, encoding="UTF-8") f.close() return newf def _makestringio(self): - return py.io.TextIO() + return TextIO() def _getcapture(self, method): if method == "fd": - return py.io.StdCaptureFD(now=False, - out=self._maketempfile(), err=self._maketempfile() + return StdCaptureFD( + now=False, + out=self._maketempfile(), + err=self._maketempfile(), ) elif method == "sys": - return py.io.StdCapture(now=False, - out=self._makestringio(), err=self._makestringio() + return StdCapture( + now=False, + out=self._makestringio(), + err=self._makestringio(), ) elif method == "no": return NoCapture() @@ -98,23 +149,24 @@ method = config._conftest.rget("option_capture", path=fspath) except KeyError: method = "fd" - if method == "fd" and not hasattr(os, 'dup'): # e.g. jython + if method == "fd" and not hasattr(os, 'dup'): # e.g. jython method = "sys" return method def reset_capturings(self): - for name, cap in self._method2capture.items(): + for cap in self._method2capture.values(): cap.reset() def resumecapture_item(self, item): method = self._getmethod(item.config, item.fspath) if not hasattr(item, 'outerr'): - item.outerr = ('', '') # we accumulate outerr on the item + item.outerr = ('', '') # we accumulate outerr on the item return self.resumecapture(method) def resumecapture(self, method=None): if hasattr(self, '_capturing'): - raise ValueError("cannot resume, already capturing with %r" % + raise ValueError( + "cannot resume, already capturing with %r" % (self._capturing,)) if method is None: method = self._defaultmethod @@ -163,8 +215,9 @@ try: self.resumecapture(method) except ValueError: - return # recursive collect, XXX refactor capturing - # to allow for more lightweight recursive capturing + # recursive collect, XXX refactor capturing + # to allow for more lightweight recursive capturing + return try: rep = __multicall__.execute() finally: @@ -205,6 +258,7 @@ error_capsysfderror = "cannot use capsys and capfd at the same time" + def pytest_funcarg__capsys(request): """enables capturing of writes to sys.stdout/sys.stderr and makes captured output available via ``capsys.readouterr()`` method calls @@ -212,7 +266,8 @@ """ if "capfd" in request._funcargs: raise request.raiseerror(error_capsysfderror) - return CaptureFixture(py.io.StdCapture) + return CaptureFixture(StdCapture) + def pytest_funcarg__capfd(request): """enables capturing of writes to file descriptors 1 and 2 and makes @@ -223,26 +278,366 @@ request.raiseerror(error_capsysfderror) if not hasattr(os, 'dup'): pytest.skip("capfd funcarg needs os.dup") - return CaptureFixture(py.io.StdCaptureFD) + return CaptureFixture(StdCaptureFD) + class CaptureFixture: def __init__(self, captureclass): - self.capture = captureclass(now=False) + self._capture = captureclass(now=False) def _start(self): - self.capture.startall() + self._capture.startall() def _finalize(self): - if hasattr(self, 'capture'): - outerr = self._outerr = self.capture.reset() - del self.capture + if hasattr(self, '_capture'): + outerr = self._outerr = self._capture.reset() + del self._capture return outerr def readouterr(self): try: - return self.capture.readouterr() + return self._capture.readouterr() except AttributeError: return self._outerr def close(self): self._finalize() + + +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 + specified a tempfile.Tempfile() will be opened + in text mode. + """ + self.targetfd = targetfd + if tmpfile is None and targetfd != 0: + f = tempfile.TemporaryFile('wb+') + tmpfile = dupfile(f, encoding="UTF-8") + f.close() + self.tmpfile = tmpfile + self._savefd = os.dup(self.targetfd) + if patchsys: + self._oldsys = getattr(sys, patchsysdict[targetfd]) + if now: + self.start() + + def start(self): + try: + os.fstat(self._savefd) + except OSError: + raise ValueError( + "saved filedescriptor not valid, " + "did you call start() twice?") + if self.targetfd == 0 and not self.tmpfile: + fd = os.open(os.devnull, os.O_RDONLY) + os.dup2(fd, 0) + os.close(fd) + if hasattr(self, '_oldsys'): + setattr(sys, patchsysdict[self.targetfd], DontReadFromInput()) + else: + os.dup2(self.tmpfile.fileno(), self.targetfd) + if hasattr(self, '_oldsys'): + setattr(sys, patchsysdict[self.targetfd], self.tmpfile) + + def done(self): + """ unpatch and clean up, returns the self.tmpfile (file object) + """ + 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 + + def writeorg(self, data): + """ write a string to the original file descriptor + """ + tempfp = tempfile.TemporaryFile() + try: + os.dup2(self._savefd, tempfp.fileno()) + tempfp.write(data) + finally: + tempfp.close() + + +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 + 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() + mode = mode or f.mode + except AttributeError: + if raising: + raise + return f + newfd = os.dup(fd) + if sys.version_info >= (3, 0): + if encoding is not None: + mode = mode.replace("b", "") + buffering = True + return os.fdopen(newfd, mode, buffering, encoding, closefd=True) + else: + f = os.fdopen(newfd, mode, buffering) + if encoding is not None: + return EncodedFile(f, encoding) + return f + + +class EncodedFile(object): + def __init__(self, _stream, encoding): + self._stream = _stream + self.encoding = encoding + + def write(self, obj): + if isinstance(obj, unicode): + obj = obj.encode(self.encoding) + self._stream.write(obj) + + def writelines(self, linelist): + data = ''.join(linelist) + self.write(data) + + def __getattr__(self, name): + return getattr(self._stream, name) + + +class Capture(object): + def call(cls, func, *args, **kwargs): + """ return a (res, out, err) tuple where + out and err represent the output/error output + during function execution. + call the given function with args/kwargs + and capture output/error during its execution. + """ + so = cls() + try: + res = func(*args, **kwargs) + finally: + out, err = so.reset() + return res, out, err + call = classmethod(call) + + def reset(self): + """ reset sys.stdout/stderr and return captured output as strings. """ + if hasattr(self, '_reset'): + raise ValueError("was already reset") + self._reset = True + outfile, errfile = self.done(save=False) + out, err = "", "" + if outfile and not outfile.closed: + out = outfile.read() + outfile.close() + if errfile and errfile != outfile and not errfile.closed: + err = errfile.read() + errfile.close() + return out, err + + def suspend(self): + """ return current snapshot captures, memorize tempfiles. """ + outerr = self.readouterr() + outfile, errfile = self.done() + return outerr + + +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. + """ + def __init__(self, out=True, err=True, mixed=False, + in_=True, patchsys=True, now=True): + self._options = { + "out": out, + "err": err, + "mixed": mixed, + "in_": in_, + "patchsys": patchsys, + "now": now, + } + self._save() + if now: + self.startall() + + def _save(self): + in_ = self._options['in_'] + out = self._options['out'] + err = self._options['err'] + mixed = self._options['mixed'] + patchsys = self._options['patchsys'] + if in_: + try: + self.in_ = FDCapture( + 0, tmpfile=None, now=False, + patchsys=patchsys) + except OSError: + pass + if out: + tmpfile = None + if hasattr(out, 'write'): + tmpfile = out + try: + self.out = FDCapture( + 1, tmpfile=tmpfile, + now=False, patchsys=patchsys) + self._options['out'] = self.out.tmpfile + except OSError: + pass + if err: + if out and mixed: + 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._options['err'] = self.err.tmpfile + except OSError: + pass + + def startall(self): + if hasattr(self, 'in_'): + self.in_.start() + if hasattr(self, 'out'): + self.out.start() + if hasattr(self, 'err'): + self.err.start() + + def resume(self): + """ resume capturing with original temp files. """ + self.startall() + + def done(self, save=True): + """ return (outfile, errfile) and stop capturing. """ + outfile = errfile = None + if hasattr(self, 'out') and not self.out.tmpfile.closed: + outfile = self.out.done() + if hasattr(self, 'err') and not self.err.tmpfile.closed: + errfile = self.err.done() + if hasattr(self, 'in_'): + self.in_.done() + if save: + self._save() + return outfile, errfile + + def readouterr(self): + """ return snapshot value of stdout/stderr capturings. """ + out = self._readsnapshot('out') + err = self._readsnapshot('err') + return out, err + + def _readsnapshot(self, name): + if hasattr(self, name): + f = getattr(self, name).tmpfile + else: + return '' + + f.seek(0) + res = f.read() + enc = getattr(f, "encoding", None) + if enc: + res = py.builtin._totext(res, enc, "replace") + f.truncate(0) + f.seek(0) + return res + + +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). + """ + def __init__(self, out=True, err=True, in_=True, mixed=False, now=True): + self._oldout = sys.stdout + self._olderr = sys.stderr + self._oldin = sys.stdin + if out and not hasattr(out, 'file'): + out = TextIO() + self.out = out + if err: + if mixed: + err = out + elif not hasattr(err, 'write'): + err = TextIO() + self.err = err + self.in_ = in_ + if now: + self.startall() + + def startall(self): + if self.out: + sys.stdout = self.out + if self.err: + sys.stderr = self.err + if self.in_: + sys.stdin = self.in_ = DontReadFromInput() + + def done(self, save=True): + """ return (outfile, errfile) and stop capturing. """ + outfile = errfile = None + if self.out and not self.out.closed: + 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 + errfile.seek(0) + if self.in_: + sys.stdin = self._oldin + return outfile, errfile + + def resume(self): + """ resume capturing with original temp files. """ + self.startall() + + def readouterr(self): + """ return snapshot value of stdout/stderr capturings. """ + out = err = "" + if self.out: + out = self.out.getvalue() + self.out.truncate(0) + self.out.seek(0) + if self.err: + err = self.err.getvalue() + self.err.truncate(0) + self.err.seek(0) + return out, err + + +class DontReadFromInput: + """Temporary stub class. Ideally when stdin is accessed, the + capturing should be turned off, with possibly all data captured + so far sent to the screen. This should be configurable, though, + because in automated test runs it is better to crash than + hang indefinitely. + """ + def read(self, *args): + raise IOError("reading from stdin while output is captured") + readline = read + readlines = read + __iter__ = read + + def fileno(self): + raise ValueError("redirected Stdin is pseudofile, has no fileno()") + + def isatty(self): + return False + + def close(self): + pass diff -r f428ddd78673080a63c59887cb4f603d29d6ed4a -r 552a700dc71f69bc5b28970ec2ff500fbaea77cb testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,8 +1,48 @@ -import pytest, py, os, sys +# note: py.io capture tests where copied from +# pylib 1.4.20.dev2 (rev 13d9af95547e) +from __future__ import with_statement +import os +import sys +import py +import pytest + +from _pytest import capture from _pytest.capture import CaptureManager +from py.builtin import print_ needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')") +if sys.version_info >= (3, 0): + def tobytes(obj): + if isinstance(obj, str): + obj = obj.encode('UTF-8') + assert isinstance(obj, bytes) + return obj + + def totext(obj): + if isinstance(obj, bytes): + obj = str(obj, 'UTF-8') + assert isinstance(obj, str) + return obj +else: + def tobytes(obj): + if isinstance(obj, unicode): + obj = obj.encode('UTF-8') + assert isinstance(obj, str) + return obj + + def totext(obj): + if isinstance(obj, str): + obj = unicode(obj, 'UTF-8') + assert isinstance(obj, unicode) + return obj + + +def oswritebytes(fd, obj): + os.write(fd, tobytes(obj)) + + + class TestCaptureManager: def test_getmethod_default_no_fd(self, testdir, monkeypatch): config = testdir.parseconfig(testdir.tmpdir) @@ -34,7 +74,7 @@ @needsosdup @pytest.mark.parametrize("method", ['no', 'fd', 'sys']) def test_capturing_basic_api(self, method): - capouter = py.io.StdCaptureFD() + capouter = capture.StdCaptureFD() old = sys.stdout, sys.stderr, sys.stdin try: capman = CaptureManager() @@ -58,7 +98,7 @@ @needsosdup def test_juggle_capturings(self, testdir): - capouter = py.io.StdCaptureFD() + capouter = capture.StdCaptureFD() try: #config = testdir.parseconfig(testdir.tmpdir) capman = CaptureManager() @@ -80,10 +120,11 @@ finally: capouter.reset() + @pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") @pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_unicode(testdir, method): - if sys.version_info >= (3,0): + if sys.version_info >= (3, 0): obj = "'b\u00f6y'" else: obj = "u'\u00f6y'" @@ -100,6 +141,7 @@ "*1 passed*" ]) + @pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_bytes_in_utf8_encoding(testdir, method): testdir.makepyfile(""" @@ -111,6 +153,7 @@ "*1 passed*" ]) + def test_collect_capturing(testdir): p = testdir.makepyfile(""" print ("collect %s failure" % 13) @@ -122,6 +165,7 @@ "*collect 13 failure*", ]) + class TestPerTestCapturing: def test_capture_and_fixtures(self, testdir): p = testdir.makepyfile(""" @@ -169,7 +213,6 @@ "in teardown*", ]) - def test_no_carry_over(self, testdir): p = testdir.makepyfile(""" def test_func1(): @@ -183,7 +226,6 @@ assert "in func1" not in s assert "in func2" in s - def test_teardown_capturing(self, testdir): p = testdir.makepyfile(""" def setup_function(function): @@ -244,13 +286,14 @@ "2", ]) + class TestLoggingInteraction: def test_logging_stream_ownership(self, testdir): p = testdir.makepyfile(""" def test_logging(): import logging import pytest - stream = py.io.TextIO() + stream = capture.TextIO() logging.basicConfig(stream=stream) stream.close() # to free memory/release resources """) @@ -320,7 +363,8 @@ logging.warn("hello432") assert 0 """) - result = testdir.runpytest(p, "--traceconfig", + result = testdir.runpytest( + p, "--traceconfig", "-p", "no:capturelog") assert result.ret != 0 result.stdout.fnmatch_lines([ @@ -461,6 +505,7 @@ "*1 error*" ]) + def test_fdfuncarg_skips_on_no_osdup(testdir): testdir.makepyfile(""" import os @@ -474,6 +519,7 @@ "*1 skipped*" ]) + def test_capture_conftest_runtest_setup(testdir): testdir.makeconftest(""" def pytest_runtest_setup(): @@ -484,6 +530,7 @@ assert result.ret == 0 assert 'hello19' not in result.stdout.str() + def test_capture_early_option_parsing(testdir): testdir.makeconftest(""" def pytest_runtest_setup(): @@ -494,9 +541,10 @@ assert result.ret == 0 assert 'hello19' in result.stdout.str() - at pytest.mark.xfail(reason='encoding issues') + + at pytest.mark.xfail(sys.version_info >= (3, 0), reason='encoding issues') def test_capture_binary_output(testdir): - testdir.makepyfile(""" + testdir.makepyfile(r""" import pytest def test_a(): @@ -516,3 +564,499 @@ '*2 passed*', ]) + +class TestTextIO: + def test_text(self): + f = capture.TextIO() + f.write("hello") + s = f.getvalue() + assert s == "hello" + f.close() + + def test_unicode_and_str_mixture(self): + f = capture.TextIO() + if sys.version_info >= (3, 0): + f.write("\u00f6") + pytest.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))") + else: + f.write(unicode("\u00f6", 'UTF-8')) + f.write("hello") # bytes + s = f.getvalue() + f.close() + assert isinstance(s, unicode) + + +def test_bytes_io(): + f = capture.BytesIO() + f.write(tobytes("hello")) + pytest.raises(TypeError, "f.write(totext('hello'))") + s = f.getvalue() + assert s == tobytes("hello") + + +def test_dontreadfrominput(): + from _pytest.capture import DontReadFromInput + f = DontReadFromInput() + assert not f.isatty() + pytest.raises(IOError, f.read) + pytest.raises(IOError, f.readlines) + pytest.raises(IOError, iter, f) + pytest.raises(ValueError, f.fileno) + f.close() # just for completeness + + +def pytest_funcarg__tmpfile(request): + testdir = request.getfuncargvalue("testdir") + f = testdir.makepyfile("").open('wb+') + request.addfinalizer(f.close) + return f + + + at needsosdup +def test_dupfile(tmpfile): + flist = [] + for i in range(5): + nf = capture.dupfile(tmpfile, encoding="utf-8") + assert nf != tmpfile + assert nf.fileno() != tmpfile.fileno() + assert nf not in flist + print_(i, end="", file=nf) + flist.append(nf) + for i in range(5): + f = flist[i] + f.close() + tmpfile.seek(0) + s = tmpfile.read() + assert "01234" in repr(s) + tmpfile.close() + + +def test_dupfile_no_mode(): + """ + dupfile should trap an AttributeError and return f if no mode is supplied. + """ + class SomeFileWrapper(object): + "An object with a fileno method but no mode attribute" + def fileno(self): + return 1 + tmpfile = SomeFileWrapper() + assert capture.dupfile(tmpfile) is tmpfile + with pytest.raises(AttributeError): + capture.dupfile(tmpfile, raising=True) + + +def lsof_check(func): + pid = os.getpid() + try: + out = py.process.cmdexec("lsof -p %d" % pid) + except py.process.cmdexec.Error: + pytest.skip("could not run 'lsof'") + func() + out2 = py.process.cmdexec("lsof -p %d" % pid) + len1 = len([x for x in out.split("\n") if "REG" in x]) + len2 = len([x for x in out2.split("\n") if "REG" in x]) + assert len2 < len1 + 3, out2 + + +class TestFDCapture: + pytestmark = needsosdup + + def test_not_now(self, tmpfile): + fd = tmpfile.fileno() + cap = capture.FDCapture(fd, now=False) + data = tobytes("hello") + os.write(fd, data) + f = cap.done() + s = f.read() + assert not s + cap = capture.FDCapture(fd, now=False) + cap.start() + os.write(fd, data) + f = cap.done() + s = f.read() + assert s == "hello" + + def test_simple(self, tmpfile): + fd = tmpfile.fileno() + cap = capture.FDCapture(fd) + data = tobytes("hello") + os.write(fd, data) + f = cap.done() + s = f.read() + assert s == "hello" + f.close() + + def test_simple_many(self, tmpfile): + for i in range(10): + self.test_simple(tmpfile) + + def test_simple_many_check_open_files(self, tmpfile): + lsof_check(lambda: self.test_simple_many(tmpfile)) + + def test_simple_fail_second_start(self, tmpfile): + fd = tmpfile.fileno() + cap = capture.FDCapture(fd) + f = cap.done() + pytest.raises(ValueError, cap.start) + f.close() + + def test_stderr(self): + cap = capture.FDCapture(2, patchsys=True) + print_("hello", file=sys.stderr) + f = cap.done() + s = f.read() + assert s == "hello\n" + + def test_stdin(self, tmpfile): + tmpfile.write(tobytes("3")) + tmpfile.seek(0) + cap = capture.FDCapture(0, tmpfile=tmpfile) + # check with os.read() directly instead of raw_input(), because + # sys.stdin itself may be redirected (as pytest now does by default) + x = os.read(0, 100).strip() + cap.done() + assert x == tobytes("3") + + def test_writeorg(self, tmpfile): + data1, data2 = tobytes("foo"), tobytes("bar") + try: + cap = capture.FDCapture(tmpfile.fileno()) + tmpfile.write(data1) + cap.writeorg(data2) + finally: + tmpfile.close() + f = cap.done() + scap = f.read() + assert scap == totext(data1) + stmp = open(tmpfile.name, 'rb').read() + assert stmp == data2 + + +class TestStdCapture: + def getcapture(self, **kw): + return capture.StdCapture(**kw) + + def test_capturing_done_simple(self): + cap = self.getcapture() + sys.stdout.write("hello") + sys.stderr.write("world") + outfile, errfile = cap.done() + s = outfile.read() + assert s == "hello" + s = errfile.read() + assert s == "world" + + def test_capturing_reset_simple(self): + cap = self.getcapture() + print("hello world") + sys.stderr.write("hello error\n") + out, err = cap.reset() + assert out == "hello world\n" + assert err == "hello error\n" + + def test_capturing_readouterr(self): + cap = self.getcapture() + try: + print ("hello world") + sys.stderr.write("hello error\n") + out, err = cap.readouterr() + assert out == "hello world\n" + assert err == "hello error\n" + sys.stderr.write("error2") + finally: + out, err = cap.reset() + assert err == "error2" + + def test_capturing_readouterr_unicode(self): + cap = self.getcapture() + try: + print ("hx\xc4\x85\xc4\x87") + out, err = cap.readouterr() + finally: + cap.reset() + assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8") + + @pytest.mark.skipif('sys.version_info >= (3,)', + reason='text output different for bytes on python3') + def test_capturing_readouterr_decode_error_handling(self): + cap = self.getcapture() + # triggered a internal error in pytest + print('\xa6') + out, err = cap.readouterr() + assert out == py.builtin._totext('\ufffd\n', 'unicode-escape') + + def test_capturing_mixed(self): + cap = self.getcapture(mixed=True) + sys.stdout.write("hello ") + sys.stderr.write("world") + sys.stdout.write(".") + out, err = cap.reset() + assert out.strip() == "hello world." + assert not err + + def test_reset_twice_error(self): + cap = self.getcapture() + print ("hello") + out, err = cap.reset() + pytest.raises(ValueError, cap.reset) + assert out == "hello\n" + assert not err + + def test_capturing_modify_sysouterr_in_between(self): + oldout = sys.stdout + olderr = sys.stderr + cap = self.getcapture() + sys.stdout.write("hello") + sys.stderr.write("world") + sys.stdout = capture.TextIO() + sys.stderr = capture.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 + + def test_capturing_error_recursive(self): + cap1 = self.getcapture() + print ("cap1") + cap2 = self.getcapture() + print ("cap2") + out2, err2 = cap2.reset() + out1, err1 = cap1.reset() + assert out1 == "cap1\n" + assert out2 == "cap2\n" + + 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 + + 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 + + def test_stdin_restored(self): + old = sys.stdin + cap = self.getcapture(in_=True) + newstdin = sys.stdin + out, err = cap.reset() + assert newstdin != sys.stdin + assert sys.stdin is old + + def test_stdin_nulled_by_default(self): + print ("XXX this test may well hang instead of crashing") + print ("XXX which indicates an error in the underlying capturing") + print ("XXX mechanisms") + cap = self.getcapture() + pytest.raises(IOError, "sys.stdin.read()") + out, err = cap.reset() + + def test_suspend_resume(self): + cap = self.getcapture(out=True, err=False, in_=False) + try: + print ("hello") + sys.stderr.write("error\n") + out, err = cap.suspend() + assert out == "hello\n" + assert not err + print ("in between") + sys.stderr.write("in between\n") + cap.resume() + print ("after") + sys.stderr.write("error_after\n") + finally: + out, err = cap.reset() + assert out == "after\n" + assert not err + + +class TestStdCaptureNotNow(TestStdCapture): + def getcapture(self, **kw): + kw['now'] = False + cap = capture.StdCapture(**kw) + cap.startall() + return cap + + +class TestStdCaptureFD(TestStdCapture): + pytestmark = needsosdup + + def getcapture(self, **kw): + return capture.StdCaptureFD(**kw) + + def test_intermingling(self): + cap = self.getcapture() + oswritebytes(1, "1") + sys.stdout.write(str(2)) + sys.stdout.flush() + oswritebytes(1, "3") + oswritebytes(2, "a") + sys.stderr.write("b") + sys.stderr.flush() + oswritebytes(2, "c") + out, err = cap.reset() + assert out == "123" + assert err == "abc" + + def test_callcapture(self): + def func(x, y): + print (x) + sys.stderr.write(str(y)) + return 42 + + res, out, err = capture.StdCaptureFD.call(func, 3, y=4) + assert res == 42 + assert out.startswith("3") + assert err.startswith("4") + + def test_many(self, capfd): + def f(): + for i in range(10): + cap = capture.StdCaptureFD() + cap.reset() + lsof_check(f) + + +class TestStdCaptureFDNotNow(TestStdCaptureFD): + pytestmark = needsosdup + + def getcapture(self, **kw): + kw['now'] = False + cap = capture.StdCaptureFD(**kw) + cap.startall() + return cap + + + at needsosdup +def test_stdcapture_fd_tmpfile(tmpfile): + capfd = capture.StdCaptureFD(out=tmpfile) + try: + os.write(1, "hello".encode("ascii")) + os.write(2, "world".encode("ascii")) + outf, errf = capfd.done() + finally: + capfd.reset() + assert outf == tmpfile + + +class TestStdCaptureFDinvalidFD: + pytestmark = needsosdup + + def test_stdcapture_fd_invalid_fd(self, testdir): + testdir.makepyfile(""" + import os + from _pytest.capture import StdCaptureFD + def test_stdout(): + os.close(1) + cap = StdCaptureFD(out=True, err=False, in_=False) + cap.done() + def test_stderr(): + os.close(2) + cap = StdCaptureFD(out=False, err=True, in_=False) + cap.done() + def test_stdin(): + os.close(0) + cap = StdCaptureFD(out=False, err=False, in_=True) + cap.done() + """) + result = testdir.runpytest("--capture=fd") + assert result.ret == 0 + assert result.parseoutcomes()['passed'] == 3 + + +def test_capture_not_started_but_reset(): + capsys = capture.StdCapture(now=False) + capsys.done() + capsys.done() + capsys.reset() + + + at needsosdup +def test_capture_no_sys(): + capsys = capture.StdCapture() + try: + cap = capture.StdCaptureFD(patchsys=False) + sys.stdout.write("hello") + sys.stderr.write("world") + oswritebytes(1, "1") + oswritebytes(2, "2") + out, err = cap.reset() + assert out == "1" + assert err == "2" + finally: + capsys.reset() + + + at needsosdup +def test_callcapture_nofd(): + def func(x, y): + oswritebytes(1, "hello") + oswritebytes(2, "hello") + print (x) + sys.stderr.write(str(y)) + return 42 + + capfd = capture.StdCaptureFD(patchsys=False) + try: + res, out, err = capture.StdCapture.call(func, 3, y=4) + finally: + capfd.reset() + assert res == 42 + assert out.startswith("3") + assert err.startswith("4") + + + at needsosdup + at pytest.mark.parametrize('use', [True, False]) +def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): + if not use: + tmpfile = True + cap = capture.StdCaptureFD(out=False, err=tmpfile, now=False) + try: + cap.startall() + capfile = cap.err.tmpfile + cap.suspend() + cap.resume() + finally: + cap.reset() + capfile2 = cap.err.tmpfile + assert capfile2 == capfile + + + at pytest.mark.parametrize('method', ['StdCapture', 'StdCaptureFD']) +def test_capturing_and_logging_fundamentals(testdir, method): + if method == "StdCaptureFD" and not hasattr(os, 'dup'): + pytest.skip("need os.dup") + # here we check a fundamental feature + p = testdir.makepyfile(""" + import sys, os + import py, logging + from _pytest import capture + cap = capture.%s(out=False, in_=False) + + logging.warn("hello1") + outerr = cap.suspend() + print ("suspend, captured %%s" %%(outerr,)) + logging.warn("hello2") + + cap.resume() + logging.warn("hello3") + + outerr = cap.suspend() + print ("suspend2, captured %%s" %% (outerr,)) + """ % (method,)) + result = testdir.runpython(p) + result.stdout.fnmatch_lines([ + "suspend, captured*hello1*", + "suspend2, captured*hello2*WARNING:root:hello3*", + ]) + assert "atexit" not in result.stderr.str() Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Sat Jan 25 09:23:39 2014 From: issues-reply at bitbucket.org (=?utf-8?q?Jurko_Gospodneti=C4=87?=) Date: Sat, 25 Jan 2014 08:23:39 -0000 Subject: [Pytest-commit] Issue #433: web site referencing the no longer used github mirror (hpk42/pytest) Message-ID: <20140125082339.31079.67780@app04.ash-private.bitbucket.org> New issue 433: web site referencing the no longer used github mirror https://bitbucket.org/hpk42/pytest/issue/433/web-site-referencing-the-no-longer-used Jurko Gospodneti?: [pytest web site](http://pytest.org/latest/) references the no longer used project github mirror in its left sidebar under *Useful Links*. Hope this helps. Best regards, Jurko Gospodneti? P.S. Where is the pytest website code stored? Had I known that, I could have prepared a pull request for this directly. From commits-noreply at bitbucket.org Sat Jan 25 10:30:35 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 25 Jan 2014 09:30:35 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140125093035.16153.26560@app03.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/dc0ad367060c/ Changeset: dc0ad367060c Branch: remove_github_references User: jurko Date: 2014-01-25 09:11:55 Summary: remove references to the no longer used github mirror Affected #: 1 file diff -r 552a700dc71f69bc5b28970ec2ff500fbaea77cb -r dc0ad367060c8b7b21353a22830897718126f5db README.rst --- a/README.rst +++ b/README.rst @@ -39,9 +39,8 @@ http://bitbucket.org/hpk42/pytest/issues/ -and checkout repos at: +and checkout repo at: - http://github.com/hpk42/pytest/ (mirror) http://bitbucket.org/hpk42/pytest/ https://bitbucket.org/hpk42/pytest/commits/87653f32a519/ Changeset: 87653f32a519 User: hpk42 Date: 2014-01-25 10:30:31 Summary: Merged in jurko/pytest/remove_github_references (pull request #112) remove references to the no longer used github mirror Affected #: 1 file diff -r 552a700dc71f69bc5b28970ec2ff500fbaea77cb -r 87653f32a519466c1172dca9e1275ffae09dbe45 README.rst --- a/README.rst +++ b/README.rst @@ -39,9 +39,8 @@ http://bitbucket.org/hpk42/pytest/issues/ -and checkout repos at: +and checkout repo at: - http://github.com/hpk42/pytest/ (mirror) http://bitbucket.org/hpk42/pytest/ Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Jan 25 11:04:57 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 25 Jan 2014 10:04:57 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20140125100457.1951.32570@app02.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/8780cd5e7247/ Changeset: 8780cd5e7247 Branch: multi-usageerror User: RonnyPfannschmidt Date: 2013-09-08 22:26:51 Summary: output errors for all failures of specific collection when issueing a command with many specific items to collect, print all collect failures instead of just the first one Affected #: 2 files diff -r e766eae72f1254187119636fb4613b03fda00d62 -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -82,8 +82,9 @@ initstate = 2 doit(config, session) except pytest.UsageError: - msg = sys.exc_info()[1].args[0] - sys.stderr.write("ERROR: %s\n" %(msg,)) + args = sys.exc_info()[1].args + for msg in args: + sys.stderr.write("ERROR: %s\n" %(msg,)) session.exitstatus = EXIT_USAGEERROR except KeyboardInterrupt: excinfo = py.code.ExceptionInfo() @@ -516,9 +517,12 @@ self.ihook.pytest_collectreport(report=rep) self.trace.root.indent -= 1 if self._notfound: + errors = [] for arg, exc in self._notfound: line = "(no name %r in any of %r)" % (arg, exc.args[0]) - raise pytest.UsageError("not found: %s\n%s" %(arg, line)) + errors.append("not found: %s\n%s" % (arg, line)) + #XXX: test this + raise pytest.UsageError(*errors) if not genitems: return rep.result else: @@ -539,8 +543,7 @@ # we are inside a make_report hook so # we cannot directly pass through the exception self._notfound.append((arg, sys.exc_info()[1])) - self.trace.root.indent -= 1 - break + self.trace.root.indent -= 1 def _collect(self, arg): diff -r e766eae72f1254187119636fb4613b03fda00d62 -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -308,6 +308,14 @@ ]) assert result.ret == 4 # usage error only if item not found + def test_report_all_failed_collections_initargs(self, testdir): + testdir.makepyfile(test_a="def", test_b="def") + result = testdir.runpytest("test_a.py::a", "test_b.py::b") + result.stderr.fnmatch_lines([ + "*ERROR*test_a.py::a*", + "*ERROR*test_b.py::b*", + ]) + class TestInvocationVariants: def test_earlyinit(self, testdir): https://bitbucket.org/hpk42/pytest/commits/e9aed57aec84/ Changeset: e9aed57aec84 Branch: multi-usageerror User: RonnyPfannschmidt Date: 2014-01-25 10:42:21 Summary: merge from default Affected #: 160 files diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 .gitignore --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ *.pyc *.pyo *.swp -*.html *.class *.orig *~ diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 .hgtags --- a/.hgtags +++ b/.hgtags @@ -60,3 +60,8 @@ 0000000000000000000000000000000000000000 1.4.14 0000000000000000000000000000000000000000 1.4.14 0000000000000000000000000000000000000000 1.4.14 +af860de70cc3f157ac34ca1d4bf557a057bff775 2.4.0 +8828c924acae0b4cad2e2cb92943d51da7cb744a 2.4.1 +8d051f89184bfa3033f5e59819dff9f32a612941 2.4.2 +a064ad64d167508a8e9e73766b1a4e6bd10c85db 2.5.0 +039d543d1ca02a716c0b0de9a7131beb8021e8a2 2.5.1 diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 .travis.yml --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,9 @@ language: python # command to install dependencies -install: "pip install 'virtualenv<1.10' -e . detox" +install: "pip install -U detox" # # command to run tests -script: detox --recreate +script: detox --recreate -i ALL=https://devpi.net/hpk/dev/ + notifications: irc: - "chat.freenode.net#pytest-dev" diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 AUTHORS --- a/AUTHORS +++ b/AUTHORS @@ -1,7 +1,7 @@ Holger Krekel, holger at merlinux eu merlinux GmbH, Germany, office at merlinux eu -Contributors include:: +Contributors include:: Ronny Pfannschmidt Benjamin Peterson @@ -9,21 +9,21 @@ Jason R. Coombs Wouter van Ackooy Samuele Pedroni -Anatoly Bubenkoff +Anatoly Bubenkoff Brianna Laugher Carl Friedrich Bolz Armin Rigo Maho -Jaap Broekhuizen +Jaap Broekhuizen Maciek Fijalkowski Guido Wesdorp Brian Dorsey Ross Lawley Ralf Schmitt -Chris Lamb +Chris Lamb Harald Armin Massa Martijn Faassen -Ian Bicking +Ian Bicking Jan Balster Grig Gheorghiu Bob Ippolito @@ -35,3 +35,6 @@ Katarzyna Jachim Christian Theunert Anthon van der Neut +Mark Abramowitz +Piotr Banaszkiewicz +Jurko Gospodneti? diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,41 +1,344 @@ -Changes between 2.3.5 and 2.4.DEV +UNRELEASED ----------------------------------- -- make "import pdb ; pdb.set_trace()" work natively wrt capturing (no "-s" needed - anymore), making ``pytest.set_trace()`` a mere shortcut. +- fix issue409 -- better interoperate with cx_freeze by not + trying to import from collections.abc which causes problems for py27/cx_freeze. + Thanks Wolfgang L. for reporting and tracking it down. -- fix issue181: --pdb now also works on collect errors (and - on internal errors) . This was implemented by a slight internal - refactoring and the introduction of a new hook - ``pytest_exception_interact`` hook (see below). +- fixed docs and code to use "pytest" instead of "py.test" almost everywhere. + Thanks Jurko Gospodnetic for the complete PR. -- fix issue341: introduce new experimental hook for IDEs/terminals to +- fix issue425: mention at end of "py.test -h" that --markers + and --fixtures work according to specified test path (or current dir) + +- fix issue413: exceptions with unicode attributes are now printed + correctly also on python2 and with pytest-xdist runs. (the fix + requires py-1.4.20) + +- copy, cleanup and integrate py.io capture + from pylib 1.4.20.dev2 (rev 13d9af95547e) + +- address issue416: clarify docs as to conftest.py loading semantics + + +- make capfd/capsys.capture private, its unused and shouldnt be exposed + + +2.5.1 +----------------------------------- + +- merge new documentation styling PR from Tobias Bieniek. + +- fix issue403: allow parametrize of multiple same-name functions within + a collection node. Thanks Andreas Kloeckner and Alex Gaynor for reporting + and analysis. + +- Allow parameterized fixtures to specify the ID of the parameters by + adding an ids argument to pytest.fixture() and pytest.yield_fixture(). + Thanks Floris Bruynooghe. + +- fix issue404 by always using the binary xml escape in the junitxml + plugin. Thanks Ronny Pfannschmidt. + +- fix issue407: fix addoption docstring to point to argparse instead of + optparse. Thanks Daniel D. Wright. + + + +2.5.0 +----------------------------------- + +- dropped python2.5 from automated release testing of pytest itself + which means it's probably going to break soon (but still works + with this release we believe). + +- simplified and fixed implementation for calling finalizers when + parametrized fixtures or function arguments are involved. finalization + is now performed lazily at setup time instead of in the "teardown phase". + While this might sound odd at first, it helps to ensure that we are + correctly handling setup/teardown even in complex code. User-level code + should not be affected unless it's implementing the pytest_runtest_teardown + hook and expecting certain fixture instances are torn down within (very + unlikely and would have been unreliable anyway). + +- PR90: add --color=yes|no|auto option to force terminal coloring + mode ("auto" is default). Thanks Marc Abramowitz. + +- fix issue319 - correctly show unicode in assertion errors. Many + thanks to Floris Bruynooghe for the complete PR. Also means + we depend on py>=1.4.19 now. + +- fix issue396 - correctly sort and finalize class-scoped parametrized + tests independently from number of methods on the class. + +- refix issue323 in a better way -- parametrization should now never + cause Runtime Recursion errors because the underlying algorithm + for re-ordering tests per-scope/per-fixture is not recursive + anymore (it was tail-call recursive before which could lead + to problems for more than >966 non-function scoped parameters). + +- fix issue290 - there is preliminary support now for parametrizing + with repeated same values (sometimes useful to to test if calling + a second time works as with the first time). + +- close issue240 - document precisely how pytest module importing + works, discuss the two common test directory layouts, and how it + interacts with PEP420-namespace packages. + +- fix issue246 fix finalizer order to be LIFO on independent fixtures + depending on a parametrized higher-than-function scoped fixture. + (was quite some effort so please bear with the complexity of this sentence :) + Thanks Ralph Schmitt for the precise failure example. + +- fix issue244 by implementing special index for parameters to only use + indices for paramentrized test ids + +- fix issue287 by running all finalizers but saving the exception + from the first failing finalizer and re-raising it so teardown will + still have failed. We reraise the first failing exception because + it might be the cause for other finalizers to fail. + +- fix ordering when mock.patch or other standard decorator-wrappings + are used with test methods. This fixues issue346 and should + help with random "xdist" collection failures. Thanks to + Ronny Pfannschmidt and Donald Stufft for helping to isolate it. + +- fix issue357 - special case "-k" expressions to allow for + filtering with simple strings that are not valid python expressions. + Examples: "-k 1.3" matches all tests parametrized with 1.3. + "-k None" filters all tests that have "None" in their name + and conversely "-k 'not None'". + Previously these examples would raise syntax errors. + +- fix issue384 by removing the trial support code + since the unittest compat enhancements allow + trial to handle it on its own + +- don't hide an ImportError when importing a plugin produces one. + fixes issue375. + +- fix issue275 - allow usefixtures and autouse fixtures + for running doctest text files. + +- fix issue380 by making --resultlog only rely on longrepr instead + of the "reprcrash" attribute which only exists sometimes. + +- address issue122: allow @pytest.fixture(params=iterator) by exploding + into a list early on. + +- fix pexpect-3.0 compatibility for pytest's own tests. + (fixes issue386) + +- allow nested parametrize-value markers, thanks James Lan for the PR. + +- fix unicode handling with new monkeypatch.setattr(import_path, value) + API. Thanks Rob Dennis. Fixes issue371. + +- fix unicode handling with junitxml, fixes issue368. + +- In assertion rewriting mode on Python 2, fix the detection of coding + cookies. See issue #330. + +- make "--runxfail" turn imperative pytest.xfail calls into no ops + (it already did neutralize pytest.mark.xfail markers) + +- refine pytest / pkg_resources interactions: The AssertionRewritingHook + PEP302 compliant loader now registers itself with setuptools/pkg_resources + properly so that the pkg_resources.resource_stream method works properly. + Fixes issue366. Thanks for the investigations and full PR to Jason R. Coombs. + +- pytestconfig fixture is now session-scoped as it is the same object during the + whole test run. Fixes issue370. + +- avoid one surprising case of marker malfunction/confusion:: + + @pytest.mark.some(lambda arg: ...) + def test_function(): + + would not work correctly because pytest assumes @pytest.mark.some + gets a function to be decorated already. We now at least detect if this + arg is an lambda and thus the example will work. Thanks Alex Gaynor + for bringing it up. + +- xfail a test on pypy that checks wrong encoding/ascii (pypy does + not error out). fixes issue385. + +- internally make varnames() deal with classes's __init__, + although it's not needed by pytest itself atm. Also + fix caching. Fixes issue376. + +- fix issue221 - handle importing of namespace-package with no + __init__.py properly. + +- refactor internal FixtureRequest handling to avoid monkeypatching. + One of the positive user-facing effects is that the "request" object + can now be used in closures. + +- fixed version comparison in pytest.importskip(modname, minverstring) + +- fix issue377 by clarifying in the nose-compat docs that pytest + does not duplicate the unittest-API into the "plain" namespace. + +- fix verbose reporting for @mock'd test functions + +v2.4.2 +----------------------------------- + +- on Windows require colorama and a newer py lib so that py.io.TerminalWriter() + now uses colorama instead of its own ctypes hacks. (fixes issue365) + thanks Paul Moore for bringing it up. + +- fix "-k" matching of tests where "repr" and "attr" and other names would + cause wrong matches because of an internal implementation quirk + (don't ask) which is now properly implemented. fixes issue345. + +- avoid tmpdir fixture to create too long filenames especially + when parametrization is used (issue354) + +- fix pytest-pep8 and pytest-flakes / pytest interactions + (collection names in mark plugin was assuming an item always + has a function which is not true for those plugins etc.) + Thanks Andi Zeidler. + +- introduce node.get_marker/node.add_marker API for plugins + like pytest-pep8 and pytest-flakes to avoid the messy + details of the node.keywords pseudo-dicts. Adapated + docs. + +- remove attempt to "dup" stdout at startup as it's icky. + the normal capturing should catch enough possibilities + of tests messing up standard FDs. + +- add pluginmanager.do_configure(config) as a link to + config.do_configure() for plugin-compatibility + +v2.4.1 +----------------------------------- + +- When using parser.addoption() unicode arguments to the + "type" keyword should also be converted to the respective types. + thanks Floris Bruynooghe, @dnozay. (fixes issue360 and issue362) + +- fix dotted filename completion when using argcomplete + thanks Anthon van der Neuth. (fixes issue361) + +- fix regression when a 1-tuple ("arg",) is used for specifying + parametrization (the values of the parametrization were passed + nested in a tuple). Thanks Donald Stufft. + +- merge doc typo fixes, thanks Andy Dirnberger + +v2.4 +----------------------------------- + +known incompatibilities: + +- if calling --genscript from python2.7 or above, you only get a + standalone script which works on python2.7 or above. Use Python2.6 + to also get a python2.5 compatible version. + +- all xunit-style teardown methods (nose-style, pytest-style, + unittest-style) will not be called if the corresponding setup method failed, + see issue322 below. + +- the pytest_plugin_unregister hook wasn't ever properly called + and there is no known implementation of the hook - so it got removed. + +- pytest.fixture-decorated functions cannot be generators (i.e. use + yield) anymore. This change might be reversed in 2.4.1 if it causes + unforeseen real-life issues. However, you can always write and return + an inner function/generator and change the fixture consumer to iterate + over the returned generator. This change was done in lieu of the new + ``pytest.yield_fixture`` decorator, see below. + +new features: + +- experimentally introduce a new ``pytest.yield_fixture`` decorator + which accepts exactly the same parameters as pytest.fixture but + mandates a ``yield`` statement instead of a ``return statement`` from + fixture functions. This allows direct integration with "with-style" + context managers in fixture functions and generally avoids registering + of finalization callbacks in favour of treating the "after-yield" as + teardown code. Thanks Andreas Pelme, Vladimir Keleshev, Floris + Bruynooghe, Ronny Pfannschmidt and many others for discussions. + +- allow boolean expression directly with skipif/xfail + if a "reason" is also specified. Rework skipping documentation + to recommend "condition as booleans" because it prevents surprises + when importing markers between modules. Specifying conditions + as strings will remain fully supported. + +- reporting: color the last line red or green depending if + failures/errors occured or everything passed. thanks Christian + Theunert. + +- make "import pdb ; pdb.set_trace()" work natively wrt capturing (no + "-s" needed anymore), making ``pytest.set_trace()`` a mere shortcut. + +- fix issue181: --pdb now also works on collect errors (and + on internal errors) . This was implemented by a slight internal + refactoring and the introduction of a new hook + ``pytest_exception_interact`` hook (see next item). + +- fix issue341: introduce new experimental hook for IDEs/terminals to intercept debugging: ``pytest_exception_interact(node, call, report)``. +- new monkeypatch.setattr() variant to provide a shorter + invocation for patching out classes/functions from modules: + + monkeypatch.setattr("requests.get", myfunc) + + will replace the "get" function of the "requests" module with ``myfunc``. + +- fix issue322: tearDownClass is not run if setUpClass failed. Thanks + Mathieu Agopian for the initial fix. Also make all of pytest/nose + finalizer mimick the same generic behaviour: if a setupX exists and + fails, don't run teardownX. This internally introduces a new method + "node.addfinalizer()" helper which can only be called during the setup + phase of a node. + +- simplify pytest.mark.parametrize() signature: allow to pass a + CSV-separated string to specify argnames. For example: + ``pytest.mark.parametrize("input,expected", [(1,2), (2,3)])`` + works as well as the previous: + ``pytest.mark.parametrize(("input", "expected"), ...)``. + +- add support for setUpModule/tearDownModule detection, thanks Brian Okken. + +- integrate tab-completion on options through use of "argcomplete". + Thanks Anthon van der Neut for the PR. + +- change option names to be hyphen-separated long options but keep the + old spelling backward compatible. py.test -h will only show the + hyphenated version, for example "--collect-only" but "--collectonly" + will remain valid as well (for backward-compat reasons). Many thanks to + Anthon van der Neut for the implementation and to Hynek Schlawack for + pushing us. + +- fix issue 308 - allow to mark/xfail/skip individual parameter sets + when parametrizing. Thanks Brianna Laugher. + +- call new experimental pytest_load_initial_conftests hook to allow + 3rd party plugins to do something before a conftest is loaded. + +Bug fixes: + +- fix issue358 - capturing options are now parsed more properly + by using a new parser.parse_known_args method. + +- pytest now uses argparse instead of optparse (thanks Anthon) which + means that "argparse" is added as a dependency if installing into python2.6 + environments or below. + +- fix issue333: fix a case of bad unittest/pytest hook interaction. + - PR27: correctly handle nose.SkipTest during collection. Thanks Antonio Cuni, Ronny Pfannschmidt. -- new monkeypatch.replace() to avoid imports and provide a shorter - invocation for patching out classes/functions from modules: - - monkeypatch.replace("requests.get", myfunc - - will replace the "get" function of the "requests" module with ``myfunc``. - -- fix issue322: tearDownClass is not run if setUpClass failed. Thanks - Mathieu Agopian for the initial fix. Also make all of pytest/nose finalizer - mimick the same generic behaviour: if a setupX exists and fails, - don't run teardownX. This also introduces a new method "node.addfinalizer()" - helper which can only be called during the setup phase of a node. +- fix issue355: junitxml puts name="pytest" attribute to testsuite tag. - fix issue336: autouse fixture in plugins should work again. -- change to use hyphen-separated long options but keep the old spelling - backward compatible. py.test -h will only show the hyphenated version, - for example "--collect-only" but "--collectonly" will remain valid as well - (for backward-compat reasons). Many thanks to Anthon van der Neut for - the implementation and to Hynek Schlawack for pushing us. - - fix issue279: improve object comparisons on assertion failure for standard datatypes and recognise collections.abc. Thanks to Brianna Laugher and Mathieu Agopian. @@ -49,19 +352,9 @@ - fix issue305: ignore any problems when writing pyc files. -- integrate tab-completion on options through use of "argcomplete". - Thanks Anthon van der Neut for the PR. - -- pytest now uses argparse instead of optparse (thanks Anthon) which - means that "argparse" is added as a dependency if installing into python2.6 - environments or below. - - SO-17664702: call fixture finalizers even if the fixture function partially failed (finalizers would not always be called before) -- color the last line red or green depending if failures/errors occured - or everything passed. thanks Christian Theunert. - - fix issue320 - fix class scope for fixtures when mixed with module-level functions. Thanks Anatloy Bubenkoff. @@ -73,35 +366,16 @@ - fix issue323 - sorting of many module-scoped arg parametrizations -- add support for setUpModule/tearDownModule detection, thanks Brian Okken. - - make sessionfinish hooks execute with the same cwd-context as at - session start (helps fix plugin behaviour which write output files + session start (helps fix plugin behaviour which write output files with relative path such as pytest-cov) - fix issue316 - properly reference collection hooks in docs -- fix issue 308 - allow to mark/xfail/skip individual parameter sets - when parametrizing. Thanks Brianna Laugher. - -- simplify parametrize() signature: allow to pass a CSV-separated string - to specify argnames. For example: ``pytest.mark.parametrize("input,expected", [(1,2), (2,3)])`` is possible now in addition to the prior - ``pytest.mark.parametrize(("input", "expected"), ...)``. - - fix issue 306 - cleanup of -k/-m options to only match markers/test names/keywords respectively. Thanks Wouter van Ackooy. -- (experimental) allow fixture functions to be - implemented as context managers. Thanks Andreas Pelme, - Vladimir Keleshev. - -- (experimental) allow boolean expression directly with skipif/xfail - if a "reason" is also specified. Rework skipping documentation - to recommend "condition as booleans" because it prevents surprises - when importing markers between modules. Specifying conditions - as strings will remain fully supported. - -- improved doctest counting for doctests in python modules -- +- improved doctest counting for doctests in python modules -- files without any doctest items will not show up anymore and doctest examples are counted as separate test items. thanks Danilo Bellini. @@ -111,7 +385,7 @@ mode. Thanks Jason R. Coombs. - fix junitxml generation when test output contains control characters, - addressing issue267, thanks Jaap Broekhuizen + addressing issue267, thanks Jaap Broekhuizen - fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho. @@ -119,15 +393,11 @@ - better parametrize error messages, thanks Brianna Laugher +- pytest_terminal_summary(terminalreporter) hooks can now use + ".section(title)" and ".line(msg)" methods to print extra + information at the end of a test run. -known incompatibilities: - -- if calling --genscript from python2.7 or above, you only get a - standalone script which works on python2.7 or above. Use Python2.6 - to also get a python2.5 compatible version. - - -Changes between 2.3.4 and 2.3.5 +v2.3.5 ----------------------------------- - fix issue169: respect --tb=style with setup/teardown errors as well. @@ -178,7 +448,7 @@ - fix bug where using capsys with pytest.set_trace() in a test function would break when looking at capsys.readouterr() -- allow to specify prefixes starting with "_" when +- allow to specify prefixes starting with "_" when customizing python_functions test discovery. (thanks Graham Horler) - improve PYTEST_DEBUG tracing output by puting @@ -192,10 +462,10 @@ - fix issue266 - accept unicode in MarkEvaluator expressions -Changes between 2.3.3 and 2.3.4 +v2.3.4 ----------------------------------- -- yielded test functions will now have autouse-fixtures active but +- yielded test functions will now have autouse-fixtures active but cannot accept fixtures as funcargs - it's anyway recommended to rather use the post-2.0 parametrize features instead of yield, see: http://pytest.org/latest/example/parametrize.html @@ -210,9 +480,9 @@ can write: -k "name1 or name2" etc. This is a slight incompatibility if you used special syntax like "TestClass.test_method" which you now need to write as -k "TestClass and test_method" to match a certain - method in a certain test class. + method in a certain test class. -Changes between 2.3.2 and 2.3.3 +v2.3.3 ----------------------------------- - fix issue214 - parse modules that contain special objects like e. g. @@ -244,10 +514,10 @@ - fix issue127 - improve documentation for pytest_addoption() and add a ``config.getoption(name)`` helper function for consistency. -Changes between 2.3.1 and 2.3.2 +v2.3.2 ----------------------------------- -- fix issue208 and fix issue29 use new py version to avoid long pauses +- fix issue208 and fix issue29 use new py version to avoid long pauses when printing tracebacks in long modules - fix issue205 - conftests in subdirs customizing @@ -277,7 +547,7 @@ - add tox.ini to pytest distribution so that ignore-dirs and others config bits are properly distributed for maintainers who run pytest-own tests -Changes between 2.3.0 and 2.3.1 +v2.3.1 ----------------------------------- - fix issue202 - fix regression: using "self" from fixture functions now @@ -290,7 +560,7 @@ - link to web pages from --markers output which provides help for pytest.mark.* usage. -Changes between 2.2.4 and 2.3.0 +v2.3.0 ----------------------------------- - fix issue202 - better automatic names for parametrized test functions @@ -331,7 +601,7 @@ - pluginmanager.register(...) now raises ValueError if the plugin has been already registered or the name is taken -- fix issue159: improve http://pytest.org/latest/faq.html +- fix issue159: improve http://pytest.org/latest/faq.html especially with respect to the "magic" history, also mention pytest-django, trial and unittest integration. @@ -362,14 +632,14 @@ you can use startdir.bestrelpath(yourpath) to show nice relative path - - allow plugins to implement both pytest_report_header and + - allow plugins to implement both pytest_report_header and pytest_sessionstart (sessionstart is invoked first). - don't show deselected reason line if there is none - py.test -vv will show all of assert comparisations instead of truncating -Changes between 2.2.3 and 2.2.4 +v2.2.4 ----------------------------------- - fix error message for rewritten assertions involving the % operator @@ -386,17 +656,17 @@ - fix issue #144: better mangle test ids to junitxml classnames - upgrade distribute_setup.py to 0.6.27 -Changes between 2.2.2 and 2.2.3 +v2.2.3 ---------------------------------------- - fix uploaded package to only include neccesary files -Changes between 2.2.1 and 2.2.2 +v2.2.2 ---------------------------------------- - fix issue101: wrong args to unittest.TestCase test function now produce better output -- fix issue102: report more useful errors and hints for when a +- fix issue102: report more useful errors and hints for when a test directory was renamed and some pyc/__pycache__ remain - fix issue106: allow parametrize to be applied multiple times e.g. from module, class and at function level. @@ -411,11 +681,11 @@ - allow adding of attributes to test reports such that it also works with distributed testing (no upgrade of pytest-xdist needed) -Changes between 2.2.0 and 2.2.1 +v2.2.1 ---------------------------------------- - fix issue99 (in pytest and py) internallerrors with resultlog now - produce better output - fixed by normalizing pytest_internalerror + produce better output - fixed by normalizing pytest_internalerror input arguments. - fix issue97 / traceback issues (in pytest and py) improve traceback output in conjunction with jinja2 and cython which hack tracebacks @@ -423,25 +693,25 @@ the final test in a test node will now run its teardown directly instead of waiting for the end of the session. Thanks Dave Hunt for the good reporting and feedback. The pytest_runtest_protocol as well - as the pytest_runtest_teardown hooks now have "nextitem" available + as the pytest_runtest_teardown hooks now have "nextitem" available which will be None indicating the end of the test run. - fix collection crash due to unknown-source collected items, thanks to Ralf Schmitt (fixed by depending on a more recent pylib) -Changes between 2.1.3 and 2.2.0 +v2.2.0 ---------------------------------------- - fix issue90: introduce eager tearing down of test items so that teardown function are called earlier. -- add an all-powerful metafunc.parametrize function which allows to +- add an all-powerful metafunc.parametrize function which allows to parametrize test function arguments in multiple steps and therefore - from indepdenent plugins and palces. + from indepdenent plugins and palces. - add a @pytest.mark.parametrize helper which allows to easily call a test function with different argument values -- Add examples to the "parametrize" example page, including a quick port +- Add examples to the "parametrize" example page, including a quick port of Test scenarios and the new parametrize function and decorator. - introduce registration for "pytest.mark.*" helpers via ini-files - or through plugin hooks. Also introduce a "--strict" option which + or through plugin hooks. Also introduce a "--strict" option which will treat unregistered markers as errors allowing to avoid typos and maintain a well described set of markers for your test suite. See exaples at http://pytest.org/latest/mark.html @@ -450,12 +720,12 @@ (this is a stricter and more predictable version of '-k' in that "-m" only matches complete markers and has more obvious rules for and/or semantics. -- new feature to help optimizing the speed of your tests: - --durations=N option for displaying N slowest test calls +- new feature to help optimizing the speed of your tests: + --durations=N option for displaying N slowest test calls and setup/teardown methods. - fix issue87: --pastebin now works with python3 - fix issue89: --pdb with unexpected exceptions in doctest work more sensibly -- fix and cleanup pytest's own test suite to not leak FDs +- fix and cleanup pytest's own test suite to not leak FDs - fix issue83: link to generated funcarg list - fix issue74: pyarg module names are now checked against imp.find_module false positives - fix compatibility with twisted/trial-11.1.0 use cases @@ -463,7 +733,7 @@ - simplify junitxml output code by relying on py.xml - add support for skip properties on unittest classes and functions -Changes between 2.1.2 and 2.1.3 +v2.1.3 ---------------------------------------- - fix issue79: assertion rewriting failed on some comparisons in boolops @@ -472,7 +742,7 @@ - fix issue75 / skipping test failure on jython - fix issue77 / Allow assertrepr_compare hook to apply to a subset of tests -Changes between 2.1.1 and 2.1.2 +v2.1.2 ---------------------------------------- - fix assertion rewriting on files with windows newlines on some Python versions @@ -482,7 +752,7 @@ - fix issue66: use different assertion rewriting caches when the -O option is passed - don't try assertion rewriting on Jython, use reinterp -Changes between 2.1.0 and 2.1.1 +v2.1.1 ---------------------------------------------- - fix issue64 / pytest.set_trace now works within pytest_generate_tests hooks @@ -495,7 +765,7 @@ - fix issue61: assertion rewriting on boolean operations with 3 or more operands - you can now build a man page with "cd doc ; make man" -Changes between 2.0.3 and 2.1.0.DEV +v2.1.0 ---------------------------------------------- - fix issue53 call nosestyle setup functions with correct ordering @@ -515,7 +785,7 @@ - report KeyboardInterrupt even if interrupted during session startup - fix issue 35 - provide PDF doc version and download link from index page -Changes between 2.0.2 and 2.0.3 +v2.0.3 ---------------------------------------------- - fix issue38: nicer tracebacks on calls to hooks, particularly early @@ -535,7 +805,7 @@ - fix issue37: avoid invalid characters in junitxml's output -Changes between 2.0.1 and 2.0.2 +v2.0.2 ---------------------------------------------- - tackle issue32 - speed up test runs of very quick test functions @@ -547,17 +817,17 @@ Also you can now access module globals from xfail/skipif expressions so that this for example works now:: - + import pytest import mymodule @pytest.mark.skipif("mymodule.__version__[0] == "1") def test_function(): pass - This will not run the test function if the module's version string + This will not run the test function if the module's version string does not start with a "1". Note that specifying a string instead - of a boolean expressions allows py.test to report meaningful information - when summarizing a test run as to what conditions lead to skipping + of a boolean expressions allows py.test to report meaningful information + when summarizing a test run as to what conditions lead to skipping (or xfail-ing) tests. - fix issue28 - setup_method and pytest_generate_tests work together @@ -580,14 +850,14 @@ - fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular thanks to Laura Creighton who also revieved parts of the documentation. -- fix slighly wrong output of verbose progress reporting for classes +- fix slighly wrong output of verbose progress reporting for classes (thanks Amaury) - more precise (avoiding of) deprecation warnings for node.Class|Function accesses - avoid std unittest assertion helper code in tracebacks (thanks Ronny) -Changes between 2.0.0 and 2.0.1 +v2.0.1 ---------------------------------------------- - refine and unify initial capturing so that it works nicely @@ -596,7 +866,7 @@ - allow to omit "()" in test ids to allow for uniform test ids as produced by Alfredo's nice pytest.vim plugin. - fix issue12 - show plugin versions with "--version" and - "--traceconfig" and also document how to add extra information + "--traceconfig" and also document how to add extra information to reporting test header - fix issue17 (import-* reporting issue on python3) by requiring py>1.4.0 (1.4.1 is going to include it) @@ -626,17 +896,17 @@ - fix issue14: no logging errors at process exit - refinements to "collecting" output on non-ttys - refine internal plugin registration and --traceconfig output -- introduce a mechanism to prevent/unregister plugins from the +- introduce a mechanism to prevent/unregister plugins from the command line, see http://pytest.org/plugins.html#cmdunregister - activate resultlog plugin by default - fix regression wrt yielded tests which due to the - collection-before-running semantics were not + collection-before-running semantics were not setup as with pytest 1.3.4. Note, however, that - the recommended and much cleaner way to do test + the recommended and much cleaner way to do test parametraization remains the "pytest_generate_tests" mechanism, see the docs. -Changes between 1.3.4 and 2.0.0 +v2.0.0 ---------------------------------------------- - pytest-2.0 is now its own package and depends on pylib-2.0 @@ -681,7 +951,7 @@ - add ability to use "class" level for cached_setup helper - fix strangeness: mark.* objects are now immutable, create new instances -Changes between 1.3.3 and 1.3.4 +v1.3.4 ---------------------------------------------- - fix issue111: improve install documentation for windows @@ -690,7 +960,7 @@ - fix issue115: unify internal exception passthrough/catching/GeneratorExit - fix issue118: new --tb=native for presenting cpython-standard exceptions -Changes between 1.3.2 and 1.3.3 +v1.3.3 ---------------------------------------------- - fix issue113: assertion representation problem with triple-quoted strings @@ -705,7 +975,7 @@ (thanks Armin Ronacher for reporting) - remove trailing whitespace in all py/text distribution files -Changes between 1.3.1 and 1.3.2 +v1.3.2 ---------------------------------------------- New features @@ -780,7 +1050,7 @@ - fix homedir detection on Windows - ship distribute_setup.py version 0.6.13 -Changes between 1.3.0 and 1.3.1 +v1.3.1 --------------------------------------------- New features @@ -852,7 +1122,7 @@ (and internally be more careful when presenting unexpected byte sequences) -Changes between 1.2.1 and 1.3.0 +v1.3.0 --------------------------------------------- - deprecate --report option in favour of a new shorter and easier to @@ -917,7 +1187,7 @@ - added links to the new capturelog and coverage plugins -Changes between 1.2.1 and 1.2.0 +v1.2.0 --------------------------------------------- - refined usage and options for "py.cleanup":: @@ -956,7 +1226,7 @@ - fix plugin links -Changes between 1.2 and 1.1.1 +v1.1.1 --------------------------------------------- - moved dist/looponfailing from py.test core into a new @@ -1040,7 +1310,7 @@ - fix docs, fix internal bin/ script generation -Changes between 1.1.1 and 1.1.0 +v1.1.0 --------------------------------------------- - introduce automatic plugin registration via 'pytest11' @@ -1059,7 +1329,7 @@ - try harder to have deprecation warnings for py.compat.* accesses report a correct location -Changes between 1.1.0 and 1.0.2 +v1.0.2 --------------------------------------------- * adjust and improve docs @@ -1144,7 +1414,7 @@ * simplified internal localpath implementation -Changes between 1.0.1 and 1.0.2 +v1.0.2 ------------------------------------------- * fixing packaging issues, triggered by fedora redhat packaging, @@ -1152,7 +1422,7 @@ * added a documentation link to the new django plugin. -Changes between 1.0.0 and 1.0.1 +v1.0.1 ------------------------------------------- * added a 'pytest_nose' plugin which handles nose.SkipTest, @@ -1186,13 +1456,13 @@ * simplified multicall mechanism and plugin architecture, renamed some internal methods and argnames -Changes between 1.0.0b9 and 1.0.0 +v1.0.0 ------------------------------------------- * 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 +v1.0.0b9 ------------------------------------------- * cleanly handle and report final teardown of test setup @@ -1226,7 +1496,7 @@ * item.repr_failure(excinfo) instead of item.repr_failure(excinfo, outerr) -Changes between 1.0.0b7 and 1.0.0b8 +v1.0.0b8 ------------------------------------------- * pytest_unittest-plugin is now enabled by default @@ -1255,7 +1525,7 @@ * tweaked doctest output for docstrings in py modules, thanks Radomir. -Changes between 1.0.0b3 and 1.0.0b7 +v1.0.0b7 ------------------------------------------- * renamed py.test.xfail back to py.test.mark.xfail to avoid @@ -1280,7 +1550,7 @@ * make __name__ == "__channelexec__" for remote_exec code -Changes between 1.0.0b1 and 1.0.0b3 +v1.0.0b3 ------------------------------------------- * plugin classes are removed: one now defines @@ -1297,7 +1567,7 @@ well with function arguments. -Changes between 0.9.2 and 1.0.0b1 +v1.0.0b1 ------------------------------------------- * introduced new "funcarg" setup method, @@ -1321,7 +1591,7 @@ XXX lots of things missing here XXX -Changes between 0.9.1 and 0.9.2 +v0.9.2 ------------------------------------------- * refined installation and metadata, created new setup.py, @@ -1354,10 +1624,10 @@ * there now is a py.__version__ attribute -Changes between 0.9.0 and 0.9.1 +v0.9.1 ------------------------------------------- -This is a fairly complete list of changes between 0.9 and 0.9.1, which can +This is a fairly complete list of v0.9.1, which can serve as a reference for developers. * allowing + signs in py.path.svn urls [39106] diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 CONTRIBUTING.rst --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,171 @@ +============ +Contributing +============ + +Contributions are highly welcomed and appreciated. Every little help counts, +so do not hesitate! + + +Types of contributions +====================== + +Report bugs +----------- + +Report bugs at https://bitbucket.org/hpk42/pytest/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting, + specifically Python interpreter version, + installed libraries and pytest version. +* Detailed steps to reproduce the bug. + +Submit feedback for developers +------------------------------ + +Do you like pytest? Share some love on Twitter or in your blog posts! + +We'd also like to hear about your propositions and suggestions. Feel free to +`submit them as issues `__ and: + +* Set the "kind" to "enhancement" or "proposal" so that we can quickly find + about them. +* Explain in detail how they should work. +* Keep the scope as narrow as possible. This will make it easier to implement. +* If you have required skills and/or knowledge, we are very happy for + :ref:`pull requests `. + + +Fix bugs +-------- + +Look through the BitBucket issues for bugs. Here is sample filter you can use: +https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=bug + +:ref:`Talk ` to developers to find out how you can fix specific bugs. + +Implement features +------------------ + +Look through the BitBucket issues for enhancements. Here is sample filter you +can use: +https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&kind=enhancement + +:ref:`Talk ` to developers to find out how you can implement specific +features. + +Write documentation +------------------- + +pytest could always use more documentation. What exactly is needed? + +* More complementary documentation. Have you perhaps found something unclear? +* Documentation translations. We currently have English and Japanese versions. +* Docstrings. There's never too much of them. +* Blog posts, articles and such -- they're all very appreciated. + +.. _pull-requests: + +Preparing Pull Requests on Bitbucket +===================================== + +.. note:: + What is a "pull request"? It informs project's core developers about the + changes you want to review and merge. Pull requests are stored on + `BitBucket servers `__. + Once you send pull request, we can discuss it's potential modifications and + even add more commits to it later on. + +The primary development platform for pytest is BitBucket. You can find all +the issues there and submit your pull requests. + +1. Fork the + `pytest BitBucket repository `__. It's + fine to use ``pytest`` as your fork repository name because it will live + under your user. + +.. _virtualenvactivate: + +2. Create and activate a fork-specific virtualenv + (http://www.virtualenv.org/en/latest/):: + + $ virtualenv pytest-venv + $ source pytest-venv/bin/activate + +.. _checkout: + +3. Clone your fork locally using `Mercurial `_ + (``hg``) and create a branch:: + + $ hg clone ssh://hg at bitbucket.org/YOUR_BITBUCKET_USERNAME/pytest + $ cd pytest + $ hg branch your-branch-name + + If you need some help with Mercurial, follow this quick start + guide: http://mercurial.selenic.com/wiki/QuickStart + +.. _testing-pytest: + +4. You can now edit your local working copy. To test you need to + install the "tox" tool into your virtualenv:: + + $ pip install tox + + You need to have Python 2.7 and 3.3 available in your system. Now + running tests is as simple as issuing this command:: + + $ python runtox.py -e py27,py33,flakes + + This command will run tests via the "tox" tool against Python 2.7 and 3.3 + and also perform "flakes" coding-style checks. ``runtox.py`` is + a thin wrapper around ``tox`` which installs from a development package + index where newer (not yet released to pypi) versions of dependencies + (especially ``py``) might be present. + + To run tests on py27 and pass options (e.g. enter pdb on failure) + to pytest you can do:: + + $ python runtox.py -e py27 -- --pdb + + or to only run tests in a particular test module on py33:: + + $ python runtox.py -e py33 -- testing/test_config.py + +5. Commit and push once your tests pass and you are happy with your change(s):: + + $ hg commit -m"" + $ hg push -b . + +6. Finally, submit a pull request through the BitBucket website: + + .. image:: img/pullrequest.png + :width: 700px + :align: center + + :: + + source: YOUR_BITBUCKET_USERNAME/pytest + branch: your-branch-name + + target: hpk42/pytest + branch: default + +.. _contribution-using-git: + +What about git (and so GitHub)? +------------------------------- + +There used to be the pytest GitHub mirror. It was removed in favor of the +Mercurial one, to remove confusion of people not knowing where it's better to +put their issues and pull requests. Also it wasn't easily possible to automate +the mirroring process. + +However, it's still possible to use git to contribute to pytest using tools +like `gitifyhg `_ which allows you to +clone and work with Mercurial repo still using git. + +.. warning:: + Remember that git is **not** a default version control system for pytest and + you need to be careful using it. diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -122,8 +122,8 @@ ------------------------------------------------------- tags: feature -- introduce py.test.mark.nocollect for not considering a function for - test collection at all. maybe also introduce a py.test.mark.test to +- introduce pytest.mark.nocollect for not considering a function for + test collection at all. maybe also introduce a pytest.mark.test to explicitely mark a function to become a tested one. Lookup JUnit ways of tagging tests. @@ -135,18 +135,18 @@ a pytest.mark.importorskip so that the test count is more correct. -introduce py.test.mark.platform +introduce pytest.mark.platform ------------------------------------------------------- tags: feature Introduce nice-to-spell platform-skipping, examples: - @py.test.mark.platform("python3") - @py.test.mark.platform("not python3") - @py.test.mark.platform("win32 and not python3") - @py.test.mark.platform("darwin") - @py.test.mark.platform("not (jython and win32)") - @py.test.mark.platform("not (jython and win32)", xfail=True) + @pytest.mark.platform("python3") + @pytest.mark.platform("not python3") + @pytest.mark.platform("win32 and not python3") + @pytest.mark.platform("darwin") + @pytest.mark.platform("not (jython and win32)") + @pytest.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 @@ -181,8 +181,8 @@ allow to name conftest.py files (in sub directories) that should be imported early, as to include command line options. -improve central py.test ini file ----------------------------------- +improve central pytest ini file +------------------------------- tags: feature introduce more declarative configuration options: @@ -196,7 +196,7 @@ ---------------------------------- tags: feature -- logo py.test +- logo pytest - examples for unittest or functional testing - resource management for functional testing - patterns: page object @@ -205,17 +205,17 @@ -------------------------------------------------------- tags: bug -With 1.1.1 py.test fails at least on windows if an import +With 1.1.1 pytest fails at least on windows if an import is relative and compared against an absolute conftest.py path. Normalize. -consider globals: py.test.ensuretemp and config +consider globals: pytest.ensuretemp and config -------------------------------------------------------------- tags: experimental-wish -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 +consider deprecating pytest.ensuretemp and pytest.config +to further reduce pytest globality. Also consider +having pytest.config and ensuretemp coming from a plugin rather than being there from the start. @@ -223,7 +223,7 @@ ----------------------------------------- tags: wish -py.test could call a new pytest_addsyspath() in order to systematically +pytest 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. @@ -232,11 +232,11 @@ -deprecate global py.test.config usage +deprecate global pytest.config usage ---------------------------------------------------------------- tags: feature -py.test.ensuretemp and py.test.config are probably the last +pytest.ensuretemp and pytest.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 diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 README.rst --- a/README.rst +++ b/README.rst @@ -1,4 +1,11 @@ -The ``py.test`` testing tool makes it easy to write small tests, yet + +Documentation: http://pytest.org/latest/ + +Changelog: http://pytest.org/latest/changelog.html + +Issues: https://bitbucket.org/hpk42/pytest/issues?status=open + +The ``pytest`` testing tool makes it easy to write small tests, yet scales to support complex functional testing. It provides - `auto-discovery @@ -7,17 +14,14 @@ - detailed info on failing `assert statements `_ (no need to remember ``self.assert*`` names) - `modular fixtures `_ for managing small or parametrized long-lived test resources. -- multi-paradigm support: you can use ``py.test`` to run test suites based +- multi-paradigm support: you can use ``pytest`` to run test suites based on `unittest `_ (or trial), `nose `_ -- single-source compatibility to Python2.4 all the way up to Python3.3, +- single-source compatibility to Python2.5 all the way up to Python3.3, PyPy-1.9 and Jython-2.5.1. - many `external plugins `_. -.. image:: https://secure.travis-ci.org/hpk42/pytest.png - :target: http://travis-ci.org/hpk42/pytest - A simple example for a test:: # content of test_module.py diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 _pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.4.0.dev12' +__version__ = '2.5.2.dev1' diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 _pytest/_argcomplete.py --- a/_pytest/_argcomplete.py +++ b/_pytest/_argcomplete.py @@ -74,9 +74,13 @@ else: prefix_dir = 0 completion = [] + globbed = [] if '*' not in prefix and '?' not in prefix: + if prefix[-1] == os.path.sep: # we are on unix, otherwise no bash + globbed.extend(glob(prefix + '.*')) prefix += '*' - for x in sorted(glob(prefix)): + globbed.extend(glob(prefix)) + for x in sorted(globbed): if os.path.isdir(x): x += '/' # append stripping the prefix (like bash, not like compgen) diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 _pytest/assertion/__init__.py --- a/_pytest/assertion/__init__.py +++ b/_pytest/assertion/__init__.py @@ -3,7 +3,6 @@ """ import py import sys -import pytest from _pytest.monkeypatch import monkeypatch from _pytest.assertion import util @@ -19,7 +18,7 @@ to provide assert expression information. """) group.addoption('--no-assert', action="store_true", default=False, dest="noassert", help="DEPRECATED equivalent to --assert=plain") - group.addoption('--nomagic', '--no-magic', action="store_true", + group.addoption('--nomagic', '--no-magic', action="store_true", default=False, help="DEPRECATED equivalent to --assert=plain") class AssertionState: @@ -35,7 +34,7 @@ mode = "plain" if mode == "rewrite": try: - import ast + import ast # noqa except ImportError: mode = "reinterp" else: @@ -49,10 +48,10 @@ m = monkeypatch() config._cleanup.append(m.undo) m.setattr(py.builtin.builtins, 'AssertionError', - reinterpret.AssertionError) + reinterpret.AssertionError) # noqa hook = None if mode == "rewrite": - hook = rewrite.AssertionRewritingHook() + hook = rewrite.AssertionRewritingHook() # noqa sys.meta_path.insert(0, hook) warn_about_missing_assertion(mode) config._assertstate = AssertionState(config, mode) @@ -79,10 +78,13 @@ for new_expl in hook_result: if new_expl: - # Don't include pageloads of data unless we are very verbose (-vv) - if len(''.join(new_expl[1:])) > 80*8 and item.config.option.verbose < 2: - new_expl[1:] = ['Detailed information truncated, use "-vv" to see'] - res = '\n~'.join(new_expl) + # Don't include pageloads of data unless we are very + # verbose (-vv) + if (len(py.builtin._totext('').join(new_expl[1:])) > 80*8 + and item.config.option.verbose < 2): + new_expl[1:] = [py.builtin._totext( + 'Detailed information truncated, use "-vv" to see')] + res = py.builtin._totext('\n~').join(new_expl) if item.config.getvalue("assertmode") == "rewrite": # The result will be fed back a python % formatting # operation, which will fail if there are extraneous @@ -102,9 +104,9 @@ def _load_modules(mode): """Lazily import assertion related code.""" global rewrite, reinterpret - from _pytest.assertion import reinterpret + from _pytest.assertion import reinterpret # noqa if mode == "rewrite": - from _pytest.assertion import rewrite + from _pytest.assertion import rewrite # noqa def warn_about_missing_assertion(mode): try: diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 _pytest/assertion/reinterpret.py --- a/_pytest/assertion/reinterpret.py +++ b/_pytest/assertion/reinterpret.py @@ -1,18 +1,26 @@ import sys import py from _pytest.assertion.util import BuiltinAssertionError +u = py.builtin._totext + class AssertionError(BuiltinAssertionError): def __init__(self, *args): BuiltinAssertionError.__init__(self, *args) if args: + # on Python2.6 we get len(args)==2 for: assert 0, (x,y) + # on Python2.7 and above we always get len(args) == 1 + # with args[0] being the (x,y) tuple. + if len(args) > 1: + toprint = args + else: + toprint = args[0] try: - self.msg = str(args[0]) - except py.builtin._sysex: - raise - except: - self.msg = "<[broken __repr__] %s at %0xd>" %( - args[0].__class__, id(args[0])) + self.msg = u(toprint) + except Exception: + self.msg = u( + "<[broken __repr__] %s at %0xd>" + % (toprint.__class__, id(toprint))) else: f = py.code.Frame(sys._getframe(1)) try: diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 _pytest/assertion/rewrite.py --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -15,7 +15,7 @@ from _pytest.assertion import util -# py.test caches rewritten pycs in __pycache__. +# pytest caches rewritten pycs in __pycache__. if hasattr(imp, "get_tag"): PYTEST_TAG = imp.get_tag() + "-PYTEST" else: @@ -41,6 +41,7 @@ def __init__(self): self.session = None self.modules = {} + self._register_with_pkg_resources() def set_session(self, session): self.fnpats = session.config.getini("python_files") @@ -55,8 +56,12 @@ names = name.rsplit(".", 1) lastname = names[-1] pth = None - if path is not None and len(path) == 1: - pth = path[0] + if path is not None: + # Starting with Python 3.3, path is a _NamespacePath(), which + # causes problems if not converted to list. + path = list(path) + if len(path) == 1: + pth = path[0] if pth is None: try: fd, fn, desc = imp.find_module(lastname, path) @@ -97,7 +102,7 @@ # the most magical part of the process: load the source, rewrite the # asserts, and load the rewritten source. We also cache the rewritten # module code in a special pyc. We must be aware of the possibility of - # concurrent py.test processes rewriting and loading pycs. To avoid + # concurrent pytest processes rewriting and loading pycs. To avoid # tricky race conditions, we maintain the following invariant: The # cached pyc is always a complete, valid pyc. Operations on it must be # atomic. POSIX's atomic rename comes in handy. @@ -169,6 +174,24 @@ tp = desc[2] return tp == imp.PKG_DIRECTORY + @classmethod + def _register_with_pkg_resources(cls): + """ + Ensure package resources can be loaded from this loader. May be called + multiple times, as the operation is idempotent. + """ + try: + import pkg_resources + # access an attribute in case a deferred importer is present + pkg_resources.__name__ + except ImportError: + return + + # Since pytest tests are always located in the file system, the + # DefaultProvider is appropriate. + pkg_resources.register_loader_type(cls, pkg_resources.DefaultProvider) + + def _write_pyc(state, co, source_path, pyc): # Technically, we don't have to have the same pyc format as # (C)Python, since these "pycs" should never be seen by builtin @@ -196,7 +219,7 @@ RN = "\r\n".encode("utf-8") N = "\n".encode("utf-8") -cookie_re = re.compile("coding[:=]\s*[-\w.]+") +cookie_re = re.compile(r"^[ \t\f]*#.*coding[:=][ \t]*[-\w.]+") BOM_UTF8 = '\xef\xbb\xbf' def _rewrite_test(state, fn): @@ -220,8 +243,8 @@ end1 = source.find("\n") end2 = source.find("\n", end1 + 1) if (not source.startswith(BOM_UTF8) and - (not cookie_re.match(source[0:end1]) or - not cookie_re.match(source[end1:end2]))): + cookie_re.match(source[0:end1]) is None and + cookie_re.match(source[end1 + 1:end2]) is None): if hasattr(state, "_indecode"): return None # encodings imported us again, we don't rewrite state._indecode = True @@ -267,7 +290,7 @@ os.rename(proc_pyc, pyc) def _read_pyc(source, pyc): - """Possibly read a py.test pyc containing rewritten code. + """Possibly read a pytest pyc containing rewritten code. Return rewritten code if successful or None if not. """ @@ -300,7 +323,7 @@ _saferepr = py.io.saferepr -from _pytest.assertion.util import format_explanation as _format_explanation +from _pytest.assertion.util import format_explanation as _format_explanation # noqa def _should_repr_global_name(obj): return not hasattr(obj, "__name__") and not py.builtin.callable(obj) @@ -538,7 +561,8 @@ for i, v in enumerate(boolop.values): if i: fail_inner = [] - self.on_failure.append(ast.If(cond, fail_inner, [])) + # cond is set in a prior loop iteration below + self.on_failure.append(ast.If(cond, fail_inner, [])) # noqa self.on_failure = fail_inner self.push_format_context() res, expl = self.visit(v) @@ -631,7 +655,7 @@ res_expr = ast.Compare(left_res, [op], [next_res]) self.statements.append(ast.Assign([store_names[i]], res_expr)) left_res, left_expl = next_res, next_expl - # Use py.code._reprcompare if that's available. + # Use pytest.assertion.util._reprcompare if that's available. expl_call = self.helper("call_reprcompare", ast.Tuple(syms, ast.Load()), ast.Tuple(load_names, ast.Load()), diff -r 8780cd5e72478006ce83e29bc618a3f2c1a2e714 -r e9aed57aec840b9ef5d9f0b9a98c39b5160450e6 _pytest/assertion/util.py --- a/_pytest/assertion/util.py +++ b/_pytest/assertion/util.py @@ -2,15 +2,12 @@ import py try: - from collections.abc import Sequence + from collections import Sequence except ImportError: - try: - from collections import Sequence - except ImportError: - Sequence = list - + Sequence = list BuiltinAssertionError = py.builtin.builtins.AssertionError +u = py.builtin._totext # The _reprcompare attribute on the util module is used by the new assertion # interpretation code and assertion rewriter to detect this plugin was @@ -29,7 +26,18 @@ for when one explanation needs to span multiple lines, e.g. when displaying diffs. """ - # simplify 'assert False where False = ...' + explanation = _collapse_false(explanation) + lines = _split_explanation(explanation) + result = _format_lines(lines) + return u('\n').join(result) + + +def _collapse_false(explanation): + """Collapse expansions of False + + So this strips out any "assert False\n{where False = ...\n}" + blocks. + """ where = 0 while True: start = where = explanation.find("False\n{False = ", where) @@ -51,28 +59,48 @@ explanation = (explanation[:start] + explanation[start+15:end-1] + explanation[end+1:]) where -= 17 - raw_lines = (explanation or '').split('\n') - # escape newlines not followed by {, } and ~ + return explanation + + +def _split_explanation(explanation): + """Return a list of individual lines in the explanation + + This will return a list of lines split on '\n{', '\n}' and '\n~'. + Any other newlines will be escaped and appear in the line as the + literal '\n' characters. + """ + raw_lines = (explanation or u('')).split('\n') lines = [raw_lines[0]] for l in raw_lines[1:]: if l.startswith('{') or l.startswith('}') or l.startswith('~'): lines.append(l) else: lines[-1] += '\\n' + l + return lines + +def _format_lines(lines): + """Format the individual lines + + This will replace the '{', '}' and '~' characters of our mini + formatting language with the proper 'where ...', 'and ...' and ' + + ...' text, taking care of indentation along the way. + + Return a list of formatted lines. + """ result = lines[:1] stack = [0] stackcnt = [0] for line in lines[1:]: if line.startswith('{'): if stackcnt[-1]: - s = 'and ' + s = u('and ') else: - s = 'where ' + s = u('where ') stack.append(len(result)) stackcnt[-1] += 1 stackcnt.append(0) - result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) + result.append(u(' +') + u(' ')*(len(stack)-1) + s + line[1:]) elif line.startswith('}'): assert line.startswith('}') stack.pop() @@ -80,9 +108,9 @@ result[stack[-1]] += line[1:] else: assert line.startswith('~') - result.append(' '*len(stack) + line[1:]) + result.append(u(' ')*len(stack) + line[1:]) assert len(stack) == 1 - return '\n'.join(result) + return result # Provide basestring in python3 @@ -97,7 +125,7 @@ width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op left_repr = py.io.saferepr(left, maxsize=int(width/2)) right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) - summary = '%s %s %s' % (left_repr, op, right_repr) + summary = u('%s %s %s') % (left_repr, op, right_repr) issequence = lambda x: (isinstance(x, (list, tuple, Sequence)) and not isinstance(x, basestring)) @@ -120,13 +148,12 @@ elif op == 'not in': if istext(left) and istext(right): explanation = _notin_text(left, right, verbose) - except py.builtin._sysex: - raise - except: + except Exception: excinfo = py.code.ExceptionInfo() explanation = [ - '(pytest_assertion plugin: representation of details failed. ' - 'Probably an object has a faulty __repr__.)', str(excinfo)] + u('(pytest_assertion plugin: representation of details failed. ' + 'Probably an object has a faulty __repr__.)'), + u(excinfo)] if not explanation: return None @@ -148,8 +175,8 @@ break if i > 42: i -= 10 # Provide some context - explanation = ['Skipping %s identical leading ' - 'characters in diff, use -v to show' % i] + explanation = [u('Skipping %s identical leading ' + 'characters in diff, use -v to show') % i] left = left[i:] right = right[i:] if len(left) == len(right): @@ -158,8 +185,8 @@ break if i > 42: i -= 10 # Provide some context - explanation += ['Skipping %s identical trailing ' - 'characters in diff, use -v to show' % i] + explanation += [u('Skipping %s identical trailing ' + 'characters in diff, use -v to show') % i] left = left[:-i] right = right[:-i] explanation += [line.strip('\n') @@ -172,16 +199,15 @@ explanation = [] for i in range(min(len(left), len(right))): if left[i] != right[i]: - explanation += ['At index %s diff: %r != %r' % - (i, left[i], right[i])] + explanation += [u('At index %s diff: %r != %r') + % (i, left[i], right[i])] break if len(left) > len(right): - explanation += [ - 'Left contains more items, first extra item: %s' % - py.io.saferepr(left[len(right)],)] + explanation += [u('Left contains more items, first extra item: %s') + % py.io.saferepr(left[len(right)],)] elif len(left) < len(right): explanation += [ - 'Right contains more items, first extra item: %s' % + u('Right contains more items, first extra item: %s') % py.io.saferepr(right[len(left)],)] return explanation # + _diff_text(py.std.pprint.pformat(left), # py.std.pprint.pformat(right)) @@ -192,11 +218,11 @@ diff_left = left - right diff_right = right - left if diff_left: - explanation.append('Extra items in the left set:') + explanation.append(u('Extra items in the left set:')) for item in diff_left: explanation.append(py.io.saferepr(item)) if diff_right: - explanation.append('Extra items in the right set:') + explanation.append(u('Extra items in the right set:')) for item in diff_right: explanation.append(py.io.saferepr(item)) return explanation @@ -207,25 +233,25 @@ common = set(left).intersection(set(right)) same = dict((k, left[k]) for k in common if left[k] == right[k]) if same and not verbose: - explanation += ['Omitting %s identical items, use -v to show' % + explanation += [u('Omitting %s identical items, use -v to show') % len(same)] elif same: - explanation += ['Common items:'] + explanation += [u('Common items:')] explanation += py.std.pprint.pformat(same).splitlines() diff = set(k for k in common if left[k] != right[k]) if diff: - explanation += ['Differing items:'] + explanation += [u('Differing items:')] for k in diff: explanation += [py.io.saferepr({k: left[k]}) + ' != ' + py.io.saferepr({k: right[k]})] extra_left = set(left) - set(right) if extra_left: - explanation.append('Left contains more items:') + explanation.append(u('Left contains more items:')) explanation.extend(py.std.pprint.pformat( dict((k, left[k]) for k in extra_left)).splitlines()) extra_right = set(right) - set(left) if extra_right: - explanation.append('Right contains more items:') + explanation.append(u('Right contains more items:')) explanation.extend(py.std.pprint.pformat( dict((k, right[k]) for k in extra_right)).splitlines()) return explanation @@ -237,14 +263,14 @@ tail = text[index+len(term):] correct_text = head + tail diff = _diff_text(correct_text, text, verbose) - newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] + newdiff = [u('%s is contained here:') % py.io.saferepr(term, maxsize=42)] for line in diff: - if line.startswith('Skipping'): + if line.startswith(u('Skipping')): continue - if line.startswith('- '): + if line.startswith(u('- ')): continue - if line.startswith('+ '): - newdiff.append(' ' + line[2:]) + if line.startswith(u('+ ')): + newdiff.append(u(' ') + line[2:]) else: newdiff.append(line) return newdiff This diff is so big that we needed to truncate the remainder. https://bitbucket.org/hpk42/pytest/commits/cd028703f029/ Changeset: cd028703f029 User: hpk42 Date: 2014-01-25 11:04:53 Summary: Merged in RonnyPfannschmidt/pytest/multi-usageerror (pull request #113) Make one usage error for every argument that fails instead of bailing at the first only Affected #: 2 files diff -r 87653f32a519466c1172dca9e1275ffae09dbe45 -r cd028703f029183cce422260040080920dabda63 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -80,8 +80,9 @@ initstate = 2 doit(config, session) except pytest.UsageError: - msg = sys.exc_info()[1].args[0] - sys.stderr.write("ERROR: %s\n" %(msg,)) + args = sys.exc_info()[1].args + for msg in args: + sys.stderr.write("ERROR: %s\n" %(msg,)) session.exitstatus = EXIT_USAGEERROR except KeyboardInterrupt: excinfo = py.code.ExceptionInfo() @@ -538,9 +539,12 @@ self.ihook.pytest_collectreport(report=rep) self.trace.root.indent -= 1 if self._notfound: + errors = [] for arg, exc in self._notfound: line = "(no name %r in any of %r)" % (arg, exc.args[0]) - raise pytest.UsageError("not found: %s\n%s" %(arg, line)) + errors.append("not found: %s\n%s" % (arg, line)) + #XXX: test this + raise pytest.UsageError(*errors) if not genitems: return rep.result else: @@ -561,8 +565,7 @@ # we are inside a make_report hook so # we cannot directly pass through the exception self._notfound.append((arg, sys.exc_info()[1])) - self.trace.root.indent -= 1 - break + self.trace.root.indent -= 1 def _collect(self, arg): diff -r 87653f32a519466c1172dca9e1275ffae09dbe45 -r cd028703f029183cce422260040080920dabda63 testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -308,6 +308,14 @@ ]) assert result.ret == 4 # usage error only if item not found + def test_report_all_failed_collections_initargs(self, testdir): + testdir.makepyfile(test_a="def", test_b="def") + result = testdir.runpytest("test_a.py::a", "test_b.py::b") + result.stderr.fnmatch_lines([ + "*ERROR*test_a.py::a*", + "*ERROR*test_b.py::b*", + ]) + def test_namespace_import_doesnt_confuse_import_hook(self, testdir): # Ref #383. Python 3.3's namespace package messed with our import hooks # Importing a module that didn't exist, even if the ImportError was Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Sun Jan 26 04:12:11 2014 From: issues-reply at bitbucket.org (Nikolaus Rath) Date: Sun, 26 Jan 2014 03:12:11 -0000 Subject: [Pytest-commit] Issue #434: Standalone test script should allow custom interpreter in shebang (hpk42/pytest) Message-ID: <20140126031211.24690.94418@app04.ash-private.bitbucket.org> New issue 434: Standalone test script should allow custom interpreter in shebang https://bitbucket.org/hpk42/pytest/issue/434/standalone-test-script-should-allow-custom Nikolaus Rath: It seems that standalone tests scripts always get a "python" shebang: ``` $ py.test-3.3 --version This is py.test version 2.5.1, imported from /home/nikratio/.local/lib/python3.3/site-packages/pytest.py $ py.test-3.3 --genscript test.py WARNING: generated script will not run on python2.6 or below due to 'argparse' dependency. Use python2.6 to generate a python2.5/6 compatible script $ head -2 test.py #! /usr/bin/env python ``` This is rather annoying if the tested module only works under Python 3.x, because users have to be instructed to explicitly call `python3 test.py`. It would be nice if there was an option to specify the interpreter used in the shebang. Maybe it should even default to the interpreter that was used when generating the test script? From commits-noreply at bitbucket.org Sun Jan 26 12:07:50 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 26 Jan 2014 11:07:50 -0000 Subject: [Pytest-commit] commit/pytest: 4 new changesets Message-ID: <20140126110750.3497.2227@app08.ash-private.bitbucket.org> 4 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/ed13d2637cdf/ Changeset: ed13d2637cdf Branch: capsimple1 User: hpk42 Date: 2014-01-25 19:42:45 Summary: remove now parameter because pytest only used now==False everywhere Affected #: 2 files diff -r cd028703f029183cce422260040080920dabda63 -r ed13d2637cdf16e33aca6f632ade29753dca4236 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -126,13 +126,11 @@ def _getcapture(self, method): if method == "fd": return StdCaptureFD( - now=False, out=self._maketempfile(), err=self._maketempfile(), ) elif method == "sys": return StdCapture( - now=False, out=self._makestringio(), err=self._makestringio(), ) @@ -283,7 +281,7 @@ class CaptureFixture: def __init__(self, captureclass): - self._capture = captureclass(now=False) + self._capture = captureclass() def _start(self): self._capture.startall() @@ -307,7 +305,7 @@ class FDCapture: """ Capture IO to/from a given os-level filedescriptor. """ - def __init__(self, targetfd, tmpfile=None, now=True, patchsys=False): + def __init__(self, targetfd, tmpfile=None, patchsys=False): """ save targetfd descriptor, and open a new temporary file there. If no tmpfile is specified a tempfile.Tempfile() will be opened @@ -322,8 +320,6 @@ self._savefd = os.dup(self.targetfd) if patchsys: self._oldsys = getattr(sys, patchsysdict[targetfd]) - if now: - self.start() def start(self): try: @@ -421,6 +417,7 @@ and capture output/error during its execution. """ so = cls() + so.startall() try: res = func(*args, **kwargs) finally: @@ -457,18 +454,15 @@ is invalid it will not be captured. """ def __init__(self, out=True, err=True, mixed=False, - in_=True, patchsys=True, now=True): + in_=True, patchsys=True): self._options = { "out": out, "err": err, "mixed": mixed, "in_": in_, "patchsys": patchsys, - "now": now, } self._save() - if now: - self.startall() def _save(self): in_ = self._options['in_'] @@ -479,7 +473,7 @@ if in_: try: self.in_ = FDCapture( - 0, tmpfile=None, now=False, + 0, tmpfile=None, patchsys=patchsys) except OSError: pass @@ -490,7 +484,7 @@ try: self.out = FDCapture( 1, tmpfile=tmpfile, - now=False, patchsys=patchsys) + patchsys=patchsys) self._options['out'] = self.out.tmpfile except OSError: pass @@ -504,7 +498,7 @@ try: self.err = FDCapture( 2, tmpfile=tmpfile, - now=False, patchsys=patchsys) + patchsys=patchsys) self._options['err'] = self.err.tmpfile except OSError: pass @@ -562,7 +556,7 @@ 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): + def __init__(self, out=True, err=True, in_=True, mixed=False): self._oldout = sys.stdout self._olderr = sys.stderr self._oldin = sys.stdin @@ -576,8 +570,6 @@ err = TextIO() self.err = err self.in_ = in_ - if now: - self.startall() def startall(self): if self.out: diff -r cd028703f029183cce422260040080920dabda63 -r ed13d2637cdf16e33aca6f632ade29753dca4236 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -661,21 +661,6 @@ class TestFDCapture: pytestmark = needsosdup - def test_not_now(self, tmpfile): - fd = tmpfile.fileno() - cap = capture.FDCapture(fd, now=False) - data = tobytes("hello") - os.write(fd, data) - f = cap.done() - s = f.read() - assert not s - cap = capture.FDCapture(fd, now=False) - cap.start() - os.write(fd, data) - f = cap.done() - s = f.read() - assert s == "hello" - def test_simple(self, tmpfile): fd = tmpfile.fileno() cap = capture.FDCapture(fd) @@ -683,8 +668,13 @@ os.write(fd, data) f = cap.done() s = f.read() + assert not s + cap = capture.FDCapture(fd) + cap.start() + os.write(fd, data) + f = cap.done() + s = f.read() assert s == "hello" - f.close() def test_simple_many(self, tmpfile): for i in range(10): @@ -702,6 +692,7 @@ def test_stderr(self): cap = capture.FDCapture(2, patchsys=True) + cap.start() print_("hello", file=sys.stderr) f = cap.done() s = f.read() @@ -711,6 +702,7 @@ tmpfile.write(tobytes("3")) tmpfile.seek(0) cap = capture.FDCapture(0, tmpfile=tmpfile) + cap.start() # check with os.read() directly instead of raw_input(), because # sys.stdin itself may be redirected (as pytest now does by default) x = os.read(0, 100).strip() @@ -721,6 +713,7 @@ data1, data2 = tobytes("foo"), tobytes("bar") try: cap = capture.FDCapture(tmpfile.fileno()) + cap.start() tmpfile.write(data1) cap.writeorg(data2) finally: @@ -734,7 +727,9 @@ class TestStdCapture: def getcapture(self, **kw): - return capture.StdCapture(**kw) + cap = capture.StdCapture(**kw) + cap.startall() + return cap def test_capturing_done_simple(self): cap = self.getcapture() @@ -879,19 +874,13 @@ assert not err -class TestStdCaptureNotNow(TestStdCapture): - def getcapture(self, **kw): - kw['now'] = False - cap = capture.StdCapture(**kw) - cap.startall() - return cap - - class TestStdCaptureFD(TestStdCapture): pytestmark = needsosdup def getcapture(self, **kw): - return capture.StdCaptureFD(**kw) + cap = capture.StdCaptureFD(**kw) + cap.startall() + return cap def test_intermingling(self): cap = self.getcapture() @@ -926,15 +915,6 @@ lsof_check(f) -class TestStdCaptureFDNotNow(TestStdCaptureFD): - pytestmark = needsosdup - - def getcapture(self, **kw): - kw['now'] = False - cap = capture.StdCaptureFD(**kw) - cap.startall() - return cap - @needsosdup def test_stdcapture_fd_tmpfile(tmpfile): @@ -974,7 +954,7 @@ def test_capture_not_started_but_reset(): - capsys = capture.StdCapture(now=False) + capsys = capture.StdCapture() capsys.done() capsys.done() capsys.reset() @@ -985,6 +965,7 @@ capsys = capture.StdCapture() try: cap = capture.StdCaptureFD(patchsys=False) + cap.startall() sys.stdout.write("hello") sys.stderr.write("world") oswritebytes(1, "1") @@ -1006,6 +987,7 @@ return 42 capfd = capture.StdCaptureFD(patchsys=False) + capfd.startall() try: res, out, err = capture.StdCapture.call(func, 3, y=4) finally: @@ -1020,7 +1002,7 @@ def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): if not use: tmpfile = True - cap = capture.StdCaptureFD(out=False, err=tmpfile, now=False) + cap = capture.StdCaptureFD(out=False, err=tmpfile) try: cap.startall() capfile = cap.err.tmpfile @@ -1042,6 +1024,7 @@ import py, logging from _pytest import capture cap = capture.%s(out=False, in_=False) + cap.startall() logging.warn("hello1") outerr = cap.suspend() https://bitbucket.org/hpk42/pytest/commits/a1c004249dce/ Changeset: a1c004249dce Branch: capsimple1 User: hpk42 Date: 2014-01-25 19:43:57 Summary: remove "StdCapture*.call" classmethod because pytest does not use it. Affected #: 2 files diff -r ed13d2637cdf16e33aca6f632ade29753dca4236 -r a1c004249dcea37a6e62768ecfbe65aefbf24647 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -409,22 +409,6 @@ class Capture(object): - def call(cls, func, *args, **kwargs): - """ return a (res, out, err) tuple where - out and err represent the output/error output - during function execution. - call the given function with args/kwargs - and capture output/error during its execution. - """ - so = cls() - so.startall() - try: - res = func(*args, **kwargs) - finally: - out, err = so.reset() - return res, out, err - call = classmethod(call) - def reset(self): """ reset sys.stdout/stderr and return captured output as strings. """ if hasattr(self, '_reset'): diff -r ed13d2637cdf16e33aca6f632ade29753dca4236 -r a1c004249dcea37a6e62768ecfbe65aefbf24647 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -896,17 +896,6 @@ assert out == "123" assert err == "abc" - def test_callcapture(self): - def func(x, y): - print (x) - sys.stderr.write(str(y)) - return 42 - - res, out, err = capture.StdCaptureFD.call(func, 3, y=4) - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") - def test_many(self, capfd): def f(): for i in range(10): @@ -978,26 +967,6 @@ @needsosdup -def test_callcapture_nofd(): - def func(x, y): - oswritebytes(1, "hello") - oswritebytes(2, "hello") - print (x) - sys.stderr.write(str(y)) - return 42 - - capfd = capture.StdCaptureFD(patchsys=False) - capfd.startall() - try: - res, out, err = capture.StdCapture.call(func, 3, y=4) - finally: - capfd.reset() - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") - - - at needsosdup @pytest.mark.parametrize('use', [True, False]) def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): if not use: https://bitbucket.org/hpk42/pytest/commits/0de40fd1fe9f/ Changeset: 0de40fd1fe9f Branch: capsimple1 User: hpk42 Date: 2014-01-25 19:56:27 Summary: remove "mixed" capturing mode which is not used by pytest Affected #: 2 files diff -r a1c004249dcea37a6e62768ecfbe65aefbf24647 -r 0de40fd1fe9fb0f8f05bd7762db5840eef0d80db _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -437,12 +437,10 @@ 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, - in_=True, patchsys=True): + def __init__(self, out=True, err=True, in_=True, patchsys=True): self._options = { "out": out, "err": err, - "mixed": mixed, "in_": in_, "patchsys": patchsys, } @@ -452,7 +450,6 @@ in_ = self._options['in_'] out = self._options['out'] err = self._options['err'] - mixed = self._options['mixed'] patchsys = self._options['patchsys'] if in_: try: @@ -473,9 +470,7 @@ except OSError: pass if err: - if out and mixed: - tmpfile = self.out.tmpfile - elif hasattr(err, 'write'): + if hasattr(err, 'write'): tmpfile = err else: tmpfile = None @@ -540,7 +535,7 @@ 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): + def __init__(self, out=True, err=True, in_=True): self._oldout = sys.stdout self._olderr = sys.stderr self._oldin = sys.stdin @@ -548,9 +543,7 @@ out = TextIO() self.out = out if err: - if mixed: - err = out - elif not hasattr(err, 'write'): + if not hasattr(err, 'write'): err = TextIO() self.err = err self.in_ = in_ diff -r a1c004249dcea37a6e62768ecfbe65aefbf24647 -r 0de40fd1fe9fb0f8f05bd7762db5840eef0d80db testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -780,15 +780,6 @@ out, err = cap.readouterr() assert out == py.builtin._totext('\ufffd\n', 'unicode-escape') - def test_capturing_mixed(self): - cap = self.getcapture(mixed=True) - sys.stdout.write("hello ") - sys.stderr.write("world") - sys.stdout.write(".") - out, err = cap.reset() - assert out.strip() == "hello world." - assert not err - def test_reset_twice_error(self): cap = self.getcapture() print ("hello") https://bitbucket.org/hpk42/pytest/commits/4f3a783d4b7a/ Changeset: 4f3a783d4b7a User: hpk42 Date: 2014-01-26 12:07:45 Summary: Merged in hpk42/pytest-capsimple/capsimple1 (pull request #115) some simplifications in capturing code Affected #: 2 files diff -r cd028703f029183cce422260040080920dabda63 -r 4f3a783d4b7afc276205d7dd3247ee91f8722a34 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -126,13 +126,11 @@ def _getcapture(self, method): if method == "fd": return StdCaptureFD( - now=False, out=self._maketempfile(), err=self._maketempfile(), ) elif method == "sys": return StdCapture( - now=False, out=self._makestringio(), err=self._makestringio(), ) @@ -283,7 +281,7 @@ class CaptureFixture: def __init__(self, captureclass): - self._capture = captureclass(now=False) + self._capture = captureclass() def _start(self): self._capture.startall() @@ -307,7 +305,7 @@ class FDCapture: """ Capture IO to/from a given os-level filedescriptor. """ - def __init__(self, targetfd, tmpfile=None, now=True, patchsys=False): + def __init__(self, targetfd, tmpfile=None, patchsys=False): """ save targetfd descriptor, and open a new temporary file there. If no tmpfile is specified a tempfile.Tempfile() will be opened @@ -322,8 +320,6 @@ self._savefd = os.dup(self.targetfd) if patchsys: self._oldsys = getattr(sys, patchsysdict[targetfd]) - if now: - self.start() def start(self): try: @@ -413,21 +409,6 @@ class Capture(object): - def call(cls, func, *args, **kwargs): - """ return a (res, out, err) tuple where - out and err represent the output/error output - during function execution. - call the given function with args/kwargs - and capture output/error during its execution. - """ - so = cls() - try: - res = func(*args, **kwargs) - finally: - out, err = so.reset() - return res, out, err - call = classmethod(call) - def reset(self): """ reset sys.stdout/stderr and return captured output as strings. """ if hasattr(self, '_reset'): @@ -456,30 +437,24 @@ 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, - in_=True, patchsys=True, now=True): + def __init__(self, out=True, err=True, in_=True, patchsys=True): self._options = { "out": out, "err": err, - "mixed": mixed, "in_": in_, "patchsys": patchsys, - "now": now, } self._save() - if now: - self.startall() def _save(self): in_ = self._options['in_'] out = self._options['out'] err = self._options['err'] - mixed = self._options['mixed'] patchsys = self._options['patchsys'] if in_: try: self.in_ = FDCapture( - 0, tmpfile=None, now=False, + 0, tmpfile=None, patchsys=patchsys) except OSError: pass @@ -490,21 +465,19 @@ try: self.out = FDCapture( 1, tmpfile=tmpfile, - now=False, patchsys=patchsys) + patchsys=patchsys) self._options['out'] = self.out.tmpfile except OSError: pass if err: - if out and mixed: - tmpfile = self.out.tmpfile - elif hasattr(err, 'write'): + if hasattr(err, 'write'): tmpfile = err else: tmpfile = None try: self.err = FDCapture( 2, tmpfile=tmpfile, - now=False, patchsys=patchsys) + patchsys=patchsys) self._options['err'] = self.err.tmpfile except OSError: pass @@ -562,7 +535,7 @@ 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): + def __init__(self, out=True, err=True, in_=True): self._oldout = sys.stdout self._olderr = sys.stderr self._oldin = sys.stdin @@ -570,14 +543,10 @@ out = TextIO() self.out = out if err: - if mixed: - err = out - elif not hasattr(err, 'write'): + if not hasattr(err, 'write'): err = TextIO() self.err = err self.in_ = in_ - if now: - self.startall() def startall(self): if self.out: diff -r cd028703f029183cce422260040080920dabda63 -r 4f3a783d4b7afc276205d7dd3247ee91f8722a34 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -661,21 +661,6 @@ class TestFDCapture: pytestmark = needsosdup - def test_not_now(self, tmpfile): - fd = tmpfile.fileno() - cap = capture.FDCapture(fd, now=False) - data = tobytes("hello") - os.write(fd, data) - f = cap.done() - s = f.read() - assert not s - cap = capture.FDCapture(fd, now=False) - cap.start() - os.write(fd, data) - f = cap.done() - s = f.read() - assert s == "hello" - def test_simple(self, tmpfile): fd = tmpfile.fileno() cap = capture.FDCapture(fd) @@ -683,8 +668,13 @@ os.write(fd, data) f = cap.done() s = f.read() + assert not s + cap = capture.FDCapture(fd) + cap.start() + os.write(fd, data) + f = cap.done() + s = f.read() assert s == "hello" - f.close() def test_simple_many(self, tmpfile): for i in range(10): @@ -702,6 +692,7 @@ def test_stderr(self): cap = capture.FDCapture(2, patchsys=True) + cap.start() print_("hello", file=sys.stderr) f = cap.done() s = f.read() @@ -711,6 +702,7 @@ tmpfile.write(tobytes("3")) tmpfile.seek(0) cap = capture.FDCapture(0, tmpfile=tmpfile) + cap.start() # check with os.read() directly instead of raw_input(), because # sys.stdin itself may be redirected (as pytest now does by default) x = os.read(0, 100).strip() @@ -721,6 +713,7 @@ data1, data2 = tobytes("foo"), tobytes("bar") try: cap = capture.FDCapture(tmpfile.fileno()) + cap.start() tmpfile.write(data1) cap.writeorg(data2) finally: @@ -734,7 +727,9 @@ class TestStdCapture: def getcapture(self, **kw): - return capture.StdCapture(**kw) + cap = capture.StdCapture(**kw) + cap.startall() + return cap def test_capturing_done_simple(self): cap = self.getcapture() @@ -785,15 +780,6 @@ out, err = cap.readouterr() assert out == py.builtin._totext('\ufffd\n', 'unicode-escape') - def test_capturing_mixed(self): - cap = self.getcapture(mixed=True) - sys.stdout.write("hello ") - sys.stderr.write("world") - sys.stdout.write(".") - out, err = cap.reset() - assert out.strip() == "hello world." - assert not err - def test_reset_twice_error(self): cap = self.getcapture() print ("hello") @@ -879,19 +865,13 @@ assert not err -class TestStdCaptureNotNow(TestStdCapture): - def getcapture(self, **kw): - kw['now'] = False - cap = capture.StdCapture(**kw) - cap.startall() - return cap - - class TestStdCaptureFD(TestStdCapture): pytestmark = needsosdup def getcapture(self, **kw): - return capture.StdCaptureFD(**kw) + cap = capture.StdCaptureFD(**kw) + cap.startall() + return cap def test_intermingling(self): cap = self.getcapture() @@ -907,17 +887,6 @@ assert out == "123" assert err == "abc" - def test_callcapture(self): - def func(x, y): - print (x) - sys.stderr.write(str(y)) - return 42 - - res, out, err = capture.StdCaptureFD.call(func, 3, y=4) - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") - def test_many(self, capfd): def f(): for i in range(10): @@ -926,15 +895,6 @@ lsof_check(f) -class TestStdCaptureFDNotNow(TestStdCaptureFD): - pytestmark = needsosdup - - def getcapture(self, **kw): - kw['now'] = False - cap = capture.StdCaptureFD(**kw) - cap.startall() - return cap - @needsosdup def test_stdcapture_fd_tmpfile(tmpfile): @@ -974,7 +934,7 @@ def test_capture_not_started_but_reset(): - capsys = capture.StdCapture(now=False) + capsys = capture.StdCapture() capsys.done() capsys.done() capsys.reset() @@ -985,6 +945,7 @@ capsys = capture.StdCapture() try: cap = capture.StdCaptureFD(patchsys=False) + cap.startall() sys.stdout.write("hello") sys.stderr.write("world") oswritebytes(1, "1") @@ -997,30 +958,11 @@ @needsosdup -def test_callcapture_nofd(): - def func(x, y): - oswritebytes(1, "hello") - oswritebytes(2, "hello") - print (x) - sys.stderr.write(str(y)) - return 42 - - capfd = capture.StdCaptureFD(patchsys=False) - try: - res, out, err = capture.StdCapture.call(func, 3, y=4) - finally: - capfd.reset() - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") - - - at needsosdup @pytest.mark.parametrize('use', [True, False]) def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): if not use: tmpfile = True - cap = capture.StdCaptureFD(out=False, err=tmpfile, now=False) + cap = capture.StdCaptureFD(out=False, err=tmpfile) try: cap.startall() capfile = cap.err.tmpfile @@ -1042,6 +984,7 @@ import py, logging from _pytest import capture cap = capture.%s(out=False, in_=False) + cap.startall() logging.warn("hello1") outerr = cap.suspend() Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sun Jan 26 12:44:29 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 26 Jan 2014 11:44:29 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: setupstate.addfinalizer(): fix docstring and remove related unit test not covering functional reality Message-ID: <20140126114429.6342.62630@app06.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/5105e627d98d/ Changeset: 5105e627d98d User: hpk42 Date: 2014-01-26 12:44:21 Summary: setupstate.addfinalizer(): fix docstring and remove related unit test not covering functional reality Affected #: 2 files diff -r 4f3a783d4b7afc276205d7dd3247ee91f8722a34 -r 5105e627d98de316ef9d414b5236e1a18e78c304 _pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -316,11 +316,10 @@ """ 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(). - if colitem is a tuple, it will be used as a key - and needs an explicit call to _callfinalizers(key) later on. """ - assert hasattr(finalizer, '__call__') - #assert colitem in self.stack + assert colitem and not isinstance(colitem, tuple) + assert callable(finalizer) + #assert colitem in self.stack # some unit tests don't setup stack :/ self._finalizers.setdefault(colitem, []).append(finalizer) def _pop_and_teardown(self): diff -r 4f3a783d4b7afc276205d7dd3247ee91f8722a34 -r 5105e627d98de316ef9d414b5236e1a18e78c304 testing/test_runner.py --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -14,20 +14,6 @@ ss._pop_and_teardown() assert not l - def test_setup_scope_None(self, testdir): - item = testdir.getitem("def test_func(): pass") - ss = runner.SetupState() - l = [1] - ss.prepare(item) - ss.addfinalizer(l.pop, colitem=None) - assert l - ss._pop_and_teardown() - assert l - ss._pop_and_teardown() - assert l - ss.teardown_all() - assert not l - def test_teardown_exact_stack_empty(self, testdir): item = testdir.getitem("def test_func(): pass") ss = runner.SetupState() Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Mon Jan 27 11:45:04 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 27 Jan 2014 10:45:04 -0000 Subject: [Pytest-commit] commit/pytest-xdist: 4 new changesets Message-ID: <20140127104504.17998.28446@app03.ash-private.bitbucket.org> 4 new commits in pytest-xdist: https://bitbucket.org/hpk42/pytest-xdist/commits/2b3f7baf4fa0/ Changeset: 2b3f7baf4fa0 User: hpk42 Date: 2014-01-27 11:37:26 Summary: a failing test for pytest issue419 Affected #: 2 files diff -r 1138fbd617e138dad6c72a6492d0b7753e61eae9 -r 2b3f7baf4fa00f49b6300e56b7c134167ab0f24d testing/test_dsession.py --- a/testing/test_dsession.py +++ b/testing/test_dsession.py @@ -6,6 +6,7 @@ ) from _pytest import main as outcome import py +import pytest import execnet XSpec = execnet.XSpec @@ -209,3 +210,16 @@ report_collection_diff(from_collection, to_collection, 1, 2) except AssertionError as e: assert py.builtin._totext(e) == error_message + + at pytest.mark.xfail(reason="duplicate test ids not supported yet") +def test_pytest_issue419(testdir): + testdir.makepyfile(""" + import pytest + + @pytest.mark.parametrize('birth_year', [1988, 1988, ]) + def test_2011_table(birth_year): + pass + """) + reprec = testdir.inline_run("-n1") + reprec.assertoutcome(passed=2) + assert 0 diff -r 1138fbd617e138dad6c72a6492d0b7753e61eae9 -r 2b3f7baf4fa00f49b6300e56b7c134167ab0f24d xdist/dsession.py --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -142,6 +142,8 @@ node.gateway.id, ) + # all collections are the same, good. + # we now create an index self.pending = col if not col: return https://bitbucket.org/hpk42/pytest-xdist/commits/d3a9df2d81a1/ Changeset: d3a9df2d81a1 User: hpk42 Date: 2014-01-27 11:37:27 Summary: remove unneccesary item2nodes data structure for load scheduling Affected #: 1 file diff -r 2b3f7baf4fa00f49b6300e56b7c134167ab0f24d -r d3a9df2d81a14b7a33b067ff64f28ebfa7df146b xdist/dsession.py --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -95,43 +95,27 @@ self.collection_is_completed = True def remove_item(self, node, item): - if item not in self.item2nodes: - raise AssertionError(item, self.item2nodes) - nodes = self.item2nodes[item] - if node in nodes: # the node might have gone down already - nodes.remove(node) - #if not nodes: - # del self.item2nodes[item] - pending = self.node2pending[node] - pending.remove(item) + node_pending = self.node2pending[node] + node_pending.remove(item) # pre-load items-to-test if the node may become ready - if self.pending and len(pending) < self.LOAD_THRESHOLD_NEWITEMS: + if self.pending and len(node_pending) < self.LOAD_THRESHOLD_NEWITEMS: item = self.pending.pop(0) - pending.append(item) - self.item2nodes.setdefault(item, []).append(node) + node_pending.append(item) node.send_runtest(item) self.log("items waiting for node: %d" %(len(self.pending))) - #self.log("item2pending still executing: %s" %(self.item2nodes,)) #self.log("node2pending: %s" %(self.node2pending,)) def remove_node(self, node): pending = self.node2pending.pop(node) - # KeyError if we didn't get an addnode() yet - for item in pending: - l = self.item2nodes[item] - l.remove(node) - if not l: - del self.item2nodes[item] if not pending: return + # the node must have crashed on the item if there are pending ones crashitem = pending.pop(0) self.pending.extend(pending) return crashitem def init_distribute(self): assert self.collection_is_completed - assert not hasattr(self, 'item2nodes') - self.item2nodes = {} # XXX allow nodes to have different collections first_node, col = list(self.node2collection.items())[0] for node, collection in self.node2collection.items(): @@ -154,7 +138,6 @@ nodeindex = i % num_available node, pending = available[nodeindex] node.send_runtest(item) - self.item2nodes.setdefault(item, []).append(node) pending.append(item) if i >= max_one_round: break https://bitbucket.org/hpk42/pytest-xdist/commits/fe461fefe08f/ Changeset: fe461fefe08f User: hpk42 Date: 2014-01-27 11:37:33 Summary: fix issue419: work with collection indices instead of node ids. This reduces network message size. Affected #: 6 files diff -r d3a9df2d81a14b7a33b067ff64f28ebfa7df146b -r fe461fefe08fb14a20b85743988b24d836ce81e1 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,10 @@ - fix pytest issue382 - produce "pytest_runtest_logstart" event again in master. Thanks Aron Curzon. +- fix pytest issue419 by sending/receiving indices into the test + collection instead of node ids (which are not neccessarily unique + for functions parametrized with duplicate values) + 1.9 ------------------------- diff -r d3a9df2d81a14b7a33b067ff64f28ebfa7df146b -r fe461fefe08fb14a20b85743988b24d836ce81e1 testing/test_dsession.py --- a/testing/test_dsession.py +++ b/testing/test_dsession.py @@ -64,9 +64,9 @@ assert sched.tests_finished() assert node1.sent == ['ALL'] assert node2.sent == ['ALL'] - sched.remove_item(node1, collection[0]) + sched.remove_item(node1, 0) assert sched.tests_finished() - sched.remove_item(node2, collection[0]) + sched.remove_item(node2, 0) assert sched.tests_finished() def test_schedule_remove_node(self): @@ -105,7 +105,7 @@ assert len(node1.sent) == 1 assert len(node2.sent) == 1 x = sorted(node1.sent + node2.sent) - assert x == collection + assert x == [0, 1] sched.remove_item(node1, node1.sent[0]) sched.remove_item(node2, node2.sent[0]) assert sched.tests_finished() @@ -126,14 +126,14 @@ sent1 = node1.sent sent2 = node2.sent chunkitems = col[:sched.ITEM_CHUNKSIZE] - assert sent1 == chunkitems - assert sent2 == chunkitems + assert (sent1 == [0,2] and sent2 == [1,3]) or ( + sent1 == [1,3] and sent2 == [0,2]) assert sched.node2pending[node1] == sent1 assert sched.node2pending[node2] == sent2 assert len(sched.pending) == 1 for node in (node1, node2): - for i in range(sched.ITEM_CHUNKSIZE): - sched.remove_item(node, "xyz") + for i in sched.node2pending[node]: + sched.remove_item(node, i) assert not sched.pending def test_add_remove_node(self): diff -r d3a9df2d81a14b7a33b067ff64f28ebfa7df146b -r fe461fefe08fb14a20b85743988b24d836ce81e1 testing/test_remote.py --- a/testing/test_remote.py +++ b/testing/test_remote.py @@ -154,7 +154,7 @@ assert ev.kwargs['topdir'] == slave.testdir.tmpdir ids = ev.kwargs['ids'] assert len(ids) == 1 - slave.sendcommand("runtests", ids=ids) + slave.sendcommand("runtests", indices=range(len(ids))) slave.sendcommand("shutdown") ev = slave.popevent("logstart") assert ev.kwargs["nodeid"].endswith("test_func") diff -r d3a9df2d81a14b7a33b067ff64f28ebfa7df146b -r fe461fefe08fb14a20b85743988b24d836ce81e1 xdist/dsession.py --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -40,15 +40,15 @@ if len(self.node2pending) >= self.numnodes: self.collection_is_completed = True - def remove_item(self, node, item): - self.node2pending[node].remove(item) + def remove_item(self, node, item_index): + self.node2pending[node].remove(item_index) def remove_node(self, node): # KeyError if we didn't get an addnode() yet pending = self.node2pending.pop(node) if not pending: return - crashitem = pending.pop(0) + crashitem = self.node2collection[node][pending.pop(0)] # XXX what about the rest of pending? return crashitem @@ -56,7 +56,7 @@ assert self.collection_is_completed for node, pending in self.node2pending.items(): node.send_runtest_all() - pending[:] = self.node2collection[node] + pending[:] = range(len(self.node2collection[node])) class LoadScheduling: LOAD_THRESHOLD_NEWITEMS = 5 @@ -94,14 +94,15 @@ if len(self.node2collection) >= self.numnodes: self.collection_is_completed = True - def remove_item(self, node, item): + def remove_item(self, node, item_index): node_pending = self.node2pending[node] - node_pending.remove(item) + assert item_index in node_pending, (item_index, node_pending) + node_pending.remove(item_index) # pre-load items-to-test if the node may become ready if self.pending and len(node_pending) < self.LOAD_THRESHOLD_NEWITEMS: - item = self.pending.pop(0) - node_pending.append(item) - node.send_runtest(item) + item_index = self.pending.pop(0) + node_pending.append(item_index) + node.send_runtest(item_index) self.log("items waiting for node: %d" %(len(self.pending))) #self.log("node2pending: %s" %(self.node2pending,)) @@ -110,7 +111,7 @@ if not pending: return # the node must have crashed on the item if there are pending ones - crashitem = pending.pop(0) + crashitem = self.collection[pending.pop(0)] self.pending.extend(pending) return crashitem @@ -128,17 +129,18 @@ # all collections are the same, good. # we now create an index - self.pending = col + self.collection = col + self.pending = range(len(col)) if not col: return available = list(self.node2pending.items()) num_available = self.numnodes max_one_round = num_available * self.ITEM_CHUNKSIZE - 1 - for i, item in enumerate(self.pending): + for i, item_index in enumerate(self.pending): nodeindex = i % num_available node, pending = available[nodeindex] - node.send_runtest(item) - pending.append(item) + node.send_runtest(item_index) + pending.append(item_index) if i >= max_one_round: break del self.pending[:i + 1] @@ -304,7 +306,7 @@ def slave_testreport(self, node, rep): if not (rep.passed and rep.when != "call"): if rep.when in ("setup", "call"): - self.sched.remove_item(node, rep.nodeid) + self.sched.remove_item(node, rep.item_index) #self.report_line("testreport %s: %s" %(rep.id, rep.status)) rep.node = node self.config.hook.pytest_runtest_logreport(report=rep) diff -r d3a9df2d81a14b7a33b067ff64f28ebfa7df146b -r fe461fefe08fb14a20b85743988b24d836ce81e1 xdist/remote.py --- a/xdist/remote.py +++ b/xdist/remote.py @@ -47,39 +47,44 @@ name, kwargs = self.channel.receive() self.log("received command %s(**%s)" % (name, kwargs)) if name == "runtests": - ids = kwargs['ids'] - for nodeid in ids: - torun.append(self._id2item[nodeid]) + torun.extend(kwargs['indices']) elif name == "runtests_all": - torun.extend(session.items) - self.log("items to run: %s" %(len(torun))) + torun.extend(range(len(session.items))) + self.log("items to run: %s" % (torun,)) while len(torun) >= 2: - item = torun.pop(0) - nextitem = torun[0] - self.config.hook.pytest_runtest_protocol(item=item, - nextitem=nextitem) + # we store item_index so that we can pick it up from the + # runtest hooks + self.run_one_test(torun) + if name == "shutdown": while torun: - self.config.hook.pytest_runtest_protocol( - item=torun.pop(0), nextitem=None) + self.run_one_test(torun) break return True + def run_one_test(self, torun): + items = self.session.items + self.item_index = torun.pop(0) + if torun: + nextitem = items[torun[0]] + else: + nextitem = None + self.config.hook.pytest_runtest_protocol( + item=items[self.item_index], + nextitem=nextitem) + def pytest_collection_finish(self, session): - self._id2item = {} - ids = [] - for item in session.items: - self._id2item[item.nodeid] = item - ids.append(item.nodeid) self.sendevent("collectionfinish", topdir=str(session.fspath), - ids=ids) + ids=[item.nodeid for item in session.items]) def pytest_runtest_logstart(self, nodeid, location): self.sendevent("logstart", nodeid=nodeid, location=location) def pytest_runtest_logreport(self, report): data = serialize_report(report) + data["item_index"] = self.item_index + assert self.session.items[self.item_index].nodeid == report.nodeid self.sendevent("testreport", data=data) def pytest_collectreport(self, report): diff -r d3a9df2d81a14b7a33b067ff64f28ebfa7df146b -r fe461fefe08fb14a20b85743988b24d836ce81e1 xdist/slavemanage.py --- a/xdist/slavemanage.py +++ b/xdist/slavemanage.py @@ -241,8 +241,8 @@ self.gateway.exit() #del self.gateway - def send_runtest(self, nodeid): - self.sendcommand("runtests", ids=[nodeid]) + def send_runtest(self, index): + self.sendcommand("runtests", indices=[index]) def send_runtest_all(self): self.sendcommand("runtests_all",) @@ -292,7 +292,10 @@ elif eventname == "logstart": self.notify_inproc(eventname, node=self, **kwargs) elif eventname in ("testreport", "collectreport", "teardownreport"): + item_index = kwargs.pop("item_index", None) rep = unserialize_report(eventname, kwargs['data']) + if item_index is not None: + rep.item_index = item_index self.notify_inproc(eventname, node=self, rep=rep) elif eventname == "collectionfinish": self.notify_inproc(eventname, node=self, ids=kwargs['ids']) @@ -307,8 +310,7 @@ self.config.pluginmanager.notify_exception(excinfo) def unserialize_report(name, reportdict): - d = reportdict if name == "testreport": - return runner.TestReport(**d) + return runner.TestReport(**reportdict) elif name == "collectreport": - return runner.CollectReport(**d) + return runner.CollectReport(**reportdict) https://bitbucket.org/hpk42/pytest-xdist/commits/05aa4f48306c/ Changeset: 05aa4f48306c User: hpk42 Date: 2014-01-27 11:37:40 Summary: send multiple "to test" indices in one network message to a slave and improve heuristics for sending chunks where the chunksize depends on the number of remaining tests rather than fixed numbers. This reduces the number of master -> node messages (but not the reverse direction) Affected #: 8 files diff -r fe461fefe08fb14a20b85743988b24d836ce81e1 -r 05aa4f48306c905ae4d183a4b337f63cc4490466 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,13 @@ collection instead of node ids (which are not neccessarily unique for functions parametrized with duplicate values) +- send multiple "to test" indices in one network message to a slave + and improve heuristics for sending chunks where the chunksize + depends on the number of remaining tests rather than fixed numbers. + This reduces the number of master -> node messages (but not the + reverse direction) + + 1.9 ------------------------- diff -r fe461fefe08fb14a20b85743988b24d836ce81e1 -r 05aa4f48306c905ae4d183a4b337f63cc4490466 setup.py --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ packages = ['xdist'], entry_points = {'pytest11': ['xdist = xdist.plugin'],}, zip_safe=False, - install_requires = ['execnet>=1.1', 'pytest>=2.3.5'], + install_requires = ['execnet>=1.1', 'pytest>=2.4.2'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', diff -r fe461fefe08fb14a20b85743988b24d836ce81e1 -r 05aa4f48306c905ae4d183a4b337f63cc4490466 testing/test_dsession.py --- a/testing/test_dsession.py +++ b/testing/test_dsession.py @@ -29,15 +29,12 @@ self.sent = [] self.gateway = MockGateway() - def send_runtest(self, nodeid): - self.sent.append(nodeid) + def send_runtest_some(self, indices): + self.sent.extend(indices) def send_runtest_all(self): self.sent.append("ALL") - def sendlist(self, items): - self.sent.extend(items) - def shutdown(self): self._shutdown=True @@ -117,17 +114,16 @@ node2 = MockNode() sched.addnode(node1) sched.addnode(node2) - sched.ITEM_CHUNKSIZE = 2 - col = ["xyz"] * (2*sched.ITEM_CHUNKSIZE +1) + col = ["xyz"] * (3) sched.addnode_collection(node1, col) sched.addnode_collection(node2, col) sched.init_distribute() #assert not sched.tests_finished() sent1 = node1.sent sent2 = node2.sent - chunkitems = col[:sched.ITEM_CHUNKSIZE] - assert (sent1 == [0,2] and sent2 == [1,3]) or ( - sent1 == [1,3] and sent2 == [0,2]) + chunkitems = col[:1] + assert (sent1 == [0] and sent2 == [1]) or ( + sent1 == [1] and sent2 == [0]) assert sched.node2pending[node1] == sent1 assert sched.node2pending[node2] == sent2 assert len(sched.pending) == 1 diff -r fe461fefe08fb14a20b85743988b24d836ce81e1 -r 05aa4f48306c905ae4d183a4b337f63cc4490466 testing/test_remote.py --- a/testing/test_remote.py +++ b/testing/test_remote.py @@ -154,7 +154,7 @@ assert ev.kwargs['topdir'] == slave.testdir.tmpdir ids = ev.kwargs['ids'] assert len(ids) == 1 - slave.sendcommand("runtests", indices=range(len(ids))) + slave.sendcommand("runtests", indices=list(range(len(ids)))) slave.sendcommand("shutdown") ev = slave.popevent("logstart") assert ev.kwargs["nodeid"].endswith("test_func") diff -r fe461fefe08fb14a20b85743988b24d836ce81e1 -r 05aa4f48306c905ae4d183a4b337f63cc4490466 tox.ini --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ [testenv] changedir=testing -deps=pytest>=2.4.2 +deps=pytest>=2.5.1 commands= py.test --junitxml={envlogdir}/junit-{envname}.xml [] [testenv:py27] diff -r fe461fefe08fb14a20b85743988b24d836ce81e1 -r 05aa4f48306c905ae4d183a4b337f63cc4490466 xdist/dsession.py --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -59,9 +59,6 @@ pending[:] = range(len(self.node2collection[node])) class LoadScheduling: - LOAD_THRESHOLD_NEWITEMS = 5 - ITEM_CHUNKSIZE = 10 - def __init__(self, numnodes, log=None): self.numnodes = numnodes self.node2pending = {} @@ -96,15 +93,24 @@ def remove_item(self, node, item_index): node_pending = self.node2pending[node] - assert item_index in node_pending, (item_index, node_pending) node_pending.remove(item_index) # pre-load items-to-test if the node may become ready - if self.pending and len(node_pending) < self.LOAD_THRESHOLD_NEWITEMS: - item_index = self.pending.pop(0) - node_pending.append(item_index) - node.send_runtest(item_index) - self.log("items waiting for node: %d" %(len(self.pending))) - #self.log("node2pending: %s" %(self.node2pending,)) + + if self.pending: + # how many nodes do we have remaining per node roughly? + num_nodes = len(self.node2pending) + # if our node goes below a heuristic minimum, fill it out to + # heuristic maximum + items_per_node_min = max( + 1, len(self.pending) // num_nodes // 4) + items_per_node_max = max( + 1, len(self.pending) // num_nodes // 2) + if len(node_pending) <= items_per_node_min: + num_send = items_per_node_max - len(node_pending) + 1 + self._send_tests(node, num_send) + + self.log("num items waiting for node:", len(self.pending)) + #self.log("node2pending:", self.node2pending) def remove_node(self, node): pending = self.node2pending.pop(node) @@ -118,8 +124,9 @@ def init_distribute(self): assert self.collection_is_completed # XXX allow nodes to have different collections - first_node, col = list(self.node2collection.items())[0] - for node, collection in self.node2collection.items(): + node_collection_items = list(self.node2collection.items()) + first_node, col = node_collection_items[0] + for node, collection in node_collection_items[1:]: report_collection_diff( col, collection, @@ -130,21 +137,25 @@ # all collections are the same, good. # we now create an index self.collection = col - self.pending = range(len(col)) + self.pending[:] = range(len(col)) if not col: return - available = list(self.node2pending.items()) - num_available = self.numnodes - max_one_round = num_available * self.ITEM_CHUNKSIZE - 1 - for i, item_index in enumerate(self.pending): - nodeindex = i % num_available - node, pending = available[nodeindex] - node.send_runtest(item_index) - pending.append(item_index) - if i >= max_one_round: - break - del self.pending[:i + 1] + # how many items per node do we have about? + items_per_node = len(self.collection) // len(self.node2pending) + # take half of it for initial distribution, at least 1 + node_chunksize = max(items_per_node // 2, 1) + # and initialize each node with a chunk of tests + for node in self.node2pending: + self._send_tests(node, node_chunksize) + #f = open("/tmp/sent", "w") + def _send_tests(self, node, num): + tests_per_node = self.pending[:num] + #print >>self.f, "sent", node, tests_per_node + if tests_per_node: + del self.pending[:num] + self.node2pending[node].extend(tests_per_node) + node.send_runtest_some(tests_per_node) def report_collection_diff(from_collection, to_collection, from_id, to_id): """Report the collected test difference between two nodes. @@ -243,7 +254,7 @@ assert callname, kwargs method = "slave_" + callname call = getattr(self, method) - self.log("calling method: %s(**%s)" % (method, kwargs)) + self.log("calling method", method, kwargs) call(**kwargs) if self.sched.tests_finished(): self.triggershutdown() diff -r fe461fefe08fb14a20b85743988b24d836ce81e1 -r 05aa4f48306c905ae4d183a4b337f63cc4490466 xdist/remote.py --- a/xdist/remote.py +++ b/xdist/remote.py @@ -24,7 +24,7 @@ def pytest_internalerror(self, excrepr): for line in str(excrepr).split("\n"): - self.log("IERROR> " + line) + self.log("IERROR>", line) def pytest_sessionstart(self, session): self.session = session @@ -45,24 +45,19 @@ torun = [] while 1: name, kwargs = self.channel.receive() - self.log("received command %s(**%s)" % (name, kwargs)) + self.log("received command", name, kwargs) if name == "runtests": torun.extend(kwargs['indices']) elif name == "runtests_all": torun.extend(range(len(session.items))) - self.log("items to run: %s" % (torun,)) - while len(torun) >= 2: - # we store item_index so that we can pick it up from the - # runtest hooks - self.run_one_test(torun) - + self.log("items to run:", torun) + while torun: + self.run_tests(torun) if name == "shutdown": - while torun: - self.run_one_test(torun) break return True - def run_one_test(self, torun): + def run_tests(self, torun): items = self.session.items self.item_index = torun.pop(0) if torun: diff -r fe461fefe08fb14a20b85743988b24d836ce81e1 -r 05aa4f48306c905ae4d183a4b337f63cc4490466 xdist/slavemanage.py --- a/xdist/slavemanage.py +++ b/xdist/slavemanage.py @@ -241,8 +241,8 @@ self.gateway.exit() #del self.gateway - def send_runtest(self, index): - self.sendcommand("runtests", indices=[index]) + def send_runtest_some(self, indices): + self.sendcommand("runtests", indices=indices) def send_runtest_all(self): self.sendcommand("runtests_all",) Repository URL: https://bitbucket.org/hpk42/pytest-xdist/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Mon Jan 27 12:39:53 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 27 Jan 2014 11:39:53 -0000 Subject: [Pytest-commit] commit/pytest-xdist: hpk42: refine distribution fractions and make it dependend on the duration Message-ID: <20140127113953.24063.28689@app02.ash-private.bitbucket.org> 1 new commit in pytest-xdist: https://bitbucket.org/hpk42/pytest-xdist/commits/5be06b2a6411/ Changeset: 5be06b2a6411 User: hpk42 Date: 2014-01-27 12:39:43 Summary: refine distribution fractions and make it dependend on the duration of the last test in a node's set. Affected #: 1 file diff -r 05aa4f48306c905ae4d183a4b337f63cc4490466 -r 5be06b2a6411b5ac468556932861c01b21bbb107 xdist/dsession.py --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -40,7 +40,7 @@ if len(self.node2pending) >= self.numnodes: self.collection_is_completed = True - def remove_item(self, node, item_index): + def remove_item(self, node, item_index, duration=0): self.node2pending[node].remove(item_index) def remove_node(self, node): @@ -91,12 +91,16 @@ if len(self.node2collection) >= self.numnodes: self.collection_is_completed = True - def remove_item(self, node, item_index): + def remove_item(self, node, item_index, duration=0): node_pending = self.node2pending[node] node_pending.remove(item_index) # pre-load items-to-test if the node may become ready if self.pending: + if duration >= 0.1 and node_pending: + # seems the node is doing long-running tests + # so let's rather wait with sending new items + return # how many nodes do we have remaining per node roughly? num_nodes = len(self.node2pending) # if our node goes below a heuristic minimum, fill it out to @@ -142,8 +146,8 @@ return # how many items per node do we have about? items_per_node = len(self.collection) // len(self.node2pending) - # take half of it for initial distribution, at least 1 - node_chunksize = max(items_per_node // 2, 1) + # take a fraction of tests for initial distribution + node_chunksize = max(items_per_node // 4, 1) # and initialize each node with a chunk of tests for node in self.node2pending: self._send_tests(node, node_chunksize) @@ -317,7 +321,7 @@ def slave_testreport(self, node, rep): if not (rep.passed and rep.when != "call"): if rep.when in ("setup", "call"): - self.sched.remove_item(node, rep.item_index) + self.sched.remove_item(node, rep.item_index, rep.duration) #self.report_line("testreport %s: %s" %(rep.id, rep.status)) rep.node = node self.config.hook.pytest_runtest_logreport(report=rep) Repository URL: https://bitbucket.org/hpk42/pytest-xdist/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Mon Jan 27 12:42:13 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 27 Jan 2014 11:42:13 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: allow positional args to tox invocation Message-ID: <20140127114213.9566.60988@app04.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/b1b6c261d9b6/ Changeset: b1b6c261d9b6 User: hpk42 Date: 2014-01-27 12:42:06 Summary: allow positional args to tox invocation Affected #: 1 file diff -r 5105e627d98de316ef9d414b5236e1a18e78c304 -r b1b6c261d9b60d168ab2930a24fb3b24a884790e tox.ini --- a/tox.ini +++ b/tox.ini @@ -24,8 +24,8 @@ mock nose commands= - py.test -n3 -rfsxX \ - --junitxml={envlogdir}/junit-{envname}.xml testing + py.test -n1 -rfsxX \ + --junitxml={envlogdir}/junit-{envname}.xml {posargs:testing} [testenv:py33-xdist] changedir=. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Mon Jan 27 12:54:31 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 27 Jan 2014 11:54:31 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: simplify loop which turns direct funcarg parametrization to indirect Message-ID: <20140127115431.11461.86156@app06.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/0d595ac74709/ Changeset: 0d595ac74709 User: hpk42 Date: 2014-01-27 12:53:44 Summary: simplify loop which turns direct funcarg parametrization to indirect Affected #: 2 files diff -r b1b6c261d9b60d168ab2930a24fb3b24a884790e -r 0d595ac74709b416ff9ff7c52bed0f8de6bb6a9b _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -372,22 +372,22 @@ # collect funcargs of all callspecs into a list of values arg2params = {} arg2scope = {} - arg2fixturedefs = metafunc._arg2fixturedefs - for param_index, callspec in enumerate(metafunc._calls): + for callspec in metafunc._calls: for argname, argvalue in callspec.funcargs.items(): - arg2params.setdefault(argname, []).append(argvalue) + assert argname not in callspec.params + callspec.params[argname] = argvalue + arg2params_list = arg2params.setdefault(argname, []) + callspec.indices[argname] = len(arg2params_list) + arg2params_list.append(argvalue) if argname not in arg2scope: - scopenum = callspec._arg2scopenum.get(argname, scopenum_function) + scopenum = callspec._arg2scopenum.get(argname, + scopenum_function) arg2scope[argname] = scopes[scopenum] - callspec.indices[argname] = param_index - - for argname in callspec.funcargs: - assert argname not in callspec.params - callspec.params.update(callspec.funcargs) callspec.funcargs.clear() # register artificial FixtureDef's so that later at test execution # time we can rely on a proper FixtureDef to exist for fixture setup. + arg2fixturedefs = metafunc._arg2fixturedefs for argname, valuelist in arg2params.items(): # if we have a scope that is higher than function we need # to make sure we only ever create an according fixturedef on diff -r b1b6c261d9b60d168ab2930a24fb3b24a884790e -r 0d595ac74709b416ff9ff7c52bed0f8de6bb6a9b testing/python/fixture.py --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -1391,6 +1391,7 @@ reprec = testdir.inline_run("-s") reprec.assertoutcome(passed=2) + class TestFixtureMarker: def test_parametrize(self, testdir): testdir.makepyfile(""" Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Tue Jan 28 15:36:07 2014 From: issues-reply at bitbucket.org (gavrie) Date: Tue, 28 Jan 2014 14:36:07 -0000 Subject: [Pytest-commit] Issue #149: virtualenv is not recreated when deps change if '-r' is used (hpk42/tox) Message-ID: <20140128143607.12250.58701@app09.ash-private.bitbucket.org> New issue 149: virtualenv is not recreated when deps change if '-r' is used https://bitbucket.org/hpk42/tox/issue/149/virtualenv-is-not-recreated-when-deps gavrie: In my tox.ini, I have the following deps: ``` deps = -rpackaging/requirements.txt ``` Normally, when deps change, the virtualenv is recreated by tox. However, when the contents of requirements.txt change, tox does not notice this and the environment is reused. A workaround would be to list the deps directly in tox.ini, but that would require duplicating the contents of the existing requirements.txt that is used by other tools. From commits-noreply at bitbucket.org Wed Jan 29 01:43:12 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 29 Jan 2014 00:43:12 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20140129004312.17348.52632@app06.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/1d6d77f0bbd4/ Changeset: 1d6d77f0bbd4 User: flub Date: 2014-01-29 01:39:04 Summary: Avoid wasted string concatenation and improve english Affected #: 1 file diff -r 0d595ac74709b416ff9ff7c52bed0f8de6bb6a9b -r 1d6d77f0bbd4777ec018209b2889ad46515a6016 _pytest/assertion/__init__.py --- a/_pytest/assertion/__init__.py +++ b/_pytest/assertion/__init__.py @@ -80,10 +80,10 @@ if new_expl: # Don't include pageloads of data unless we are very # verbose (-vv) - if (len(py.builtin._totext('').join(new_expl[1:])) > 80*8 + if (sum(len(p) for p in new_expl[1:]) > 80*8 and item.config.option.verbose < 2): new_expl[1:] = [py.builtin._totext( - 'Detailed information truncated, use "-vv" to see')] + 'Detailed information truncated, use "-vv" to show')] res = py.builtin._totext('\n~').join(new_expl) if item.config.getvalue("assertmode") == "rewrite": # The result will be fed back a python % formatting https://bitbucket.org/hpk42/pytest/commits/30dbac953dd3/ Changeset: 30dbac953dd3 User: flub Date: 2014-01-29 01:42:58 Summary: Fix assertrepr for mojibake If the compared text was in bytes and not actually valid text (i.e. could not be encoded to text/unicode using the default encoding) then the assertrepr would fail with an EncodingError. This ensures that the internal string is always valid unicode, converting any bytes safely to valid unicode. This is done using repr() which then needs post-processing to fix the encompassing quotes and un-escape newlines. This fixes issue 429. Affected #: 2 files diff -r 1d6d77f0bbd4777ec018209b2889ad46515a6016 -r 30dbac953dd3b24dbd29b9d472ff7504011e210a _pytest/assertion/util.py --- a/_pytest/assertion/util.py +++ b/_pytest/assertion/util.py @@ -162,12 +162,18 @@ def _diff_text(left, right, verbose=False): - """Return the explanation for the diff between text + """Return the explanation for the diff between text or bytes Unless --verbose is used this will skip leading and trailing characters which are identical to keep the diff minimal. + + If the input are bytes they will be safely converted to text. """ explanation = [] + if isinstance(left, py.builtin.bytes): + left = u(repr(left)[1:-1]).replace(r'\n', '\n') + if isinstance(right, py.builtin.bytes): + right = u(repr(right)[1:-1]).replace(r'\n', '\n') if not verbose: i = 0 # just in case left or right has zero length for i in range(min(len(left), len(right))): diff -r 1d6d77f0bbd4777ec018209b2889ad46515a6016 -r 30dbac953dd3b24dbd29b9d472ff7504011e210a testing/test_assertion.py --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -185,6 +185,19 @@ assert expl[1] == py.builtin._totext('- ??', 'utf-8') assert expl[2] == py.builtin._totext('+ ?', 'utf-8') + def test_mojibake(self): + # issue 429 + left = 'e' + right = '\xc3\xa9' + if not isinstance(left, py.builtin.bytes): + left = py.builtin.bytes(left, 'utf-8') + right = py.builtin.bytes(right, 'utf-8') + expl = callequal(left, right) + for line in expl: + assert isinstance(line, py.builtin.text) + msg = py.builtin._totext('\n').join(expl) + assert msg + def test_python25_compile_issue257(testdir): testdir.makepyfile(""" Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 29 09:05:46 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 29 Jan 2014 08:05:46 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: add changelog entry about issue429, adapt README Message-ID: <20140129080546.30684.6439@app13.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/0b5c70a8ee57/ Changeset: 0b5c70a8ee57 User: hpk42 Date: 2014-01-29 09:00:14 Summary: add changelog entry about issue429, adapt README Affected #: 2 files diff -r 30dbac953dd3b24dbd29b9d472ff7504011e210a -r 0b5c70a8ee571a2d518a2c7c3733098f2326425e CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,8 @@ ----------------------------------- - fix issue409 -- better interoperate with cx_freeze by not - trying to import from collections.abc which causes problems for py27/cx_freeze. - Thanks Wolfgang L. for reporting and tracking it down. + trying to import from collections.abc which causes problems + for py27/cx_freeze. Thanks Wolfgang L. for reporting and tracking it down. - fixed docs and code to use "pytest" instead of "py.test" almost everywhere. Thanks Jurko Gospodnetic for the complete PR. @@ -20,6 +20,8 @@ - address issue416: clarify docs as to conftest.py loading semantics +- fix issue429: comparing byte strings with non-ascii chars in assert + expressions now work better. Thanks Floris Bruynooghe. - make capfd/capsys.capture private, its unused and shouldnt be exposed diff -r 30dbac953dd3b24dbd29b9d472ff7504011e210a -r 0b5c70a8ee571a2d518a2c7c3733098f2326425e README.rst --- a/README.rst +++ b/README.rst @@ -39,10 +39,10 @@ http://bitbucket.org/hpk42/pytest/issues/ -and checkout repo at: +and checkout or fork repo at: http://bitbucket.org/hpk42/pytest/ -Copyright Holger Krekel and others, 2004-2013 +Copyright Holger Krekel and others, 2004-2014 Licensed under the MIT license. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 29 10:20:22 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 29 Jan 2014 09:20:22 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix flakes failures Message-ID: <20140129092022.30312.15331@app08.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/e9b0d7ba6a50/ Changeset: e9b0d7ba6a50 User: hpk42 Date: 2014-01-29 10:20:13 Summary: fix flakes failures Affected #: 5 files diff -r 0b5c70a8ee571a2d518a2c7c3733098f2326425e -r e9b0d7ba6a503702bbfcca9189a9e01ca20f673c testing/test_assertrewrite.py --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -415,7 +415,7 @@ reason='packages without __init__.py not supported on python 2') def test_package_without__init__py(self, testdir): pkg = testdir.mkdir('a_package_without_init_py') - mod = pkg.join('module.py').ensure() + pkg.join('module.py').ensure() testdir.makepyfile("import a_package_without_init_py.module") assert testdir.runpytest().ret == 0 diff -r 0b5c70a8ee571a2d518a2c7c3733098f2326425e -r e9b0d7ba6a503702bbfcca9189a9e01ca20f673c testing/test_nose.py --- a/testing/test_nose.py +++ b/testing/test_nose.py @@ -1,4 +1,4 @@ -import py, pytest +import pytest def setup_module(mod): mod.nose = pytest.importorskip("nose") diff -r 0b5c70a8ee571a2d518a2c7c3733098f2326425e -r e9b0d7ba6a503702bbfcca9189a9e01ca20f673c testing/test_pytester.py --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -1,4 +1,3 @@ -import py import pytest import os from _pytest.pytester import HookRecorder diff -r 0b5c70a8ee571a2d518a2c7c3733098f2326425e -r e9b0d7ba6a503702bbfcca9189a9e01ca20f673c testing/test_session.py --- a/testing/test_session.py +++ b/testing/test_session.py @@ -1,4 +1,4 @@ -import pytest, py +import pytest class SessionTests: def test_basic_testitem_events(self, testdir): diff -r 0b5c70a8ee571a2d518a2c7c3733098f2326425e -r e9b0d7ba6a503702bbfcca9189a9e01ca20f673c testing/test_tmpdir.py --- a/testing/test_tmpdir.py +++ b/testing/test_tmpdir.py @@ -1,4 +1,4 @@ -import py, pytest +import pytest from _pytest.tmpdir import tmpdir, TempdirHandler Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 29 13:47:24 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 29 Jan 2014 12:47:24 -0000 Subject: [Pytest-commit] commit/pytest: 4 new changesets Message-ID: <20140129124724.11889.83680@app07.ash-private.bitbucket.org> 4 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/375d0e5f1395/ Changeset: 375d0e5f1395 User: hpk42 Date: 2014-01-29 11:18:15 Summary: refactor lsof checking and fix an lsof leak in pypy Affected #: 1 file diff -r e9b0d7ba6a503702bbfcca9189a9e01ca20f673c -r 375d0e5f139590c1fb9700c113c0f44f2fd72497 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -5,6 +5,7 @@ import sys import py import pytest +import contextlib from _pytest import capture from _pytest.capture import CaptureManager @@ -121,9 +122,10 @@ capouter.reset() - at pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") @pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_unicode(testdir, method): + if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (2,2): + pytest.xfail("does not work on pypy < 2.2") if sys.version_info >= (3, 0): obj = "'b\u00f6y'" else: @@ -605,12 +607,12 @@ f.close() # just for completeness -def pytest_funcarg__tmpfile(request): - testdir = request.getfuncargvalue("testdir") + at pytest.yield_fixture +def tmpfile(testdir): f = testdir.makepyfile("").open('wb+') - request.addfinalizer(f.close) - return f - + yield f + if not f.closed: + f.close() @needsosdup def test_dupfile(tmpfile): @@ -645,13 +647,14 @@ capture.dupfile(tmpfile, raising=True) -def lsof_check(func): + at contextlib.contextmanager +def lsof_check(): pid = os.getpid() try: out = py.process.cmdexec("lsof -p %d" % pid) except py.process.cmdexec.Error: pytest.skip("could not run 'lsof'") - func() + yield out2 = py.process.cmdexec("lsof -p %d" % pid) len1 = len([x for x in out.split("\n") if "REG" in x]) len2 = len([x for x in out2.split("\n") if "REG" in x]) @@ -668,6 +671,7 @@ os.write(fd, data) f = cap.done() s = f.read() + f.close() assert not s cap = capture.FDCapture(fd) cap.start() @@ -675,13 +679,16 @@ f = cap.done() s = f.read() assert s == "hello" + f.close() def test_simple_many(self, tmpfile): for i in range(10): self.test_simple(tmpfile) - def test_simple_many_check_open_files(self, tmpfile): - lsof_check(lambda: self.test_simple_many(tmpfile)) + def test_simple_many_check_open_files(self, testdir): + with lsof_check(): + with testdir.makepyfile("").open('wb+') as tmpfile: + self.test_simple_many(tmpfile) def test_simple_fail_second_start(self, tmpfile): fd = tmpfile.fileno() @@ -888,12 +895,10 @@ assert err == "abc" def test_many(self, capfd): - def f(): + with lsof_check(): for i in range(10): cap = capture.StdCaptureFD() cap.reset() - lsof_check(f) - @needsosdup https://bitbucket.org/hpk42/pytest/commits/f3a9bf08c714/ Changeset: f3a9bf08c714 User: hpk42 Date: 2014-01-29 11:46:36 Summary: refine skipif to use direct booleans, to help with flakes Affected #: 2 files diff -r 375d0e5f139590c1fb9700c113c0f44f2fd72497 -r f3a9bf08c714cb0b7fbbf13010d5a5266b86db60 testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -177,7 +177,8 @@ assert result.ret != 0 assert "should be seen" in result.stdout.str() - @pytest.mark.skipif("not hasattr(py.path.local, 'mksymlinkto')") + @pytest.mark.skipif(not hasattr(py.path.local, 'mksymlinkto'), + reason="symlink not available on this platform") def test_chdir(self, testdir): testdir.tmpdir.join("py").mksymlinkto(py._pydir) p = testdir.tmpdir.join("main.py") diff -r 375d0e5f139590c1fb9700c113c0f44f2fd72497 -r f3a9bf08c714cb0b7fbbf13010d5a5266b86db60 testing/test_tmpdir.py --- a/testing/test_tmpdir.py +++ b/testing/test_tmpdir.py @@ -1,3 +1,4 @@ +import py import pytest from _pytest.tmpdir import tmpdir, TempdirHandler @@ -71,7 +72,8 @@ assert result.ret == 0 assert mytemp.join('hello').check() - at pytest.mark.skipif("not hasattr(py.path.local, 'mksymlinkto')") + at pytest.mark.skipif(not hasattr(py.path.local, 'mksymlinkto'), + reason="symlink not available on this platform") def test_tmpdir_always_is_realpath(testdir): # the reason why tmpdir should be a realpath is that # when you cd to it and do "os.getcwd()" you will anyway https://bitbucket.org/hpk42/pytest/commits/fbc05fb4bc71/ Changeset: fbc05fb4bc71 User: hpk42 Date: 2014-01-29 13:11:40 Summary: require py>=1.2.20 Affected #: 2 files diff -r f3a9bf08c714cb0b7fbbf13010d5a5266b86db60 -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 setup.py --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ long_description = open("README.rst").read() def main(): - install_requires = ["py>=1.4.20.dev2"] + install_requires = ["py>=1.4.20"] if sys.version_info < (2,7): install_requires.append("argparse") if sys.platform == "win32": diff -r f3a9bf08c714cb0b7fbbf13010d5a5266b86db60 -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 testing/test_assertrewrite.py --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -411,8 +411,8 @@ testdir.tmpdir.join("test_newlines.py").write(b, "wb") assert testdir.runpytest().ret == 0 - @pytest.mark.skipif(sys.version_info[0] == 2, - reason='packages without __init__.py not supported on python 2') + @pytest.mark.skipif(sys.version_info < (3,3), + reason='packages without __init__.py not supported on python 2') def test_package_without__init__py(self, testdir): pkg = testdir.mkdir('a_package_without_init_py') pkg.join('module.py').ensure() https://bitbucket.org/hpk42/pytest/commits/1a190672b6cc/ Changeset: 1a190672b6cc User: hpk42 Date: 2014-01-29 13:47:11 Summary: add release announcement, bump version to 2.5.2, add links to plugins index, regenerate doc examples. Affected #: 28 files diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -UNRELEASED +2.5.2 ----------------------------------- - fix issue409 -- better interoperate with cx_freeze by not diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 _pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.5.2.dev1' +__version__ = '2.5.2' diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/_templates/links.html --- a/doc/en/_templates/links.html +++ b/doc/en/_templates/links.html @@ -4,6 +4,7 @@
  • Contribution Guide
  • pytest @ PyPI
  • pytest @ Bitbucket
  • +
  • 3rd party plugins (beta)
  • Issue Tracker
  • PDF Documentation diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/announce/index.txt --- a/doc/en/announce/index.txt +++ b/doc/en/announce/index.txt @@ -5,6 +5,7 @@ .. toctree:: :maxdepth: 2 + release-2.5.2 release-2.5.1 release-2.5.0 release-2.4.2 diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/announce/release-2.5.2.txt --- /dev/null +++ b/doc/en/announce/release-2.5.2.txt @@ -0,0 +1,64 @@ +pytest-2.5.2: fixes +=========================================================================== + +pytest is a mature Python testing tool with more than a 1000 tests +against itself, passing on many different interpreters and platforms. + +The 2.5.2 release fixes a few bugs with two maybe-bugs remaining and +actively being worked on (and waiting for the bug reporter's input). +We also have a new contribution guide thanks to Piotr Banaszkiewicz +and others. + +See docs at: + + http://pytest.org + +As usual, you can upgrade from pypi via:: + + pip install -U pytest + +Thanks to the following people who contributed to this release: + + Anatoly Bubenkov + Ronny Pfannschmidt + Floris Bruynooghe + Bruno Oliveira + Andreas Pelme + Jurko Gospodneti? + Piotr Banaszkiewicz + Simon Liedtke + lakka + Lukasz Balcerzak + Philippe Muller + Daniel Hahler + +have fun, +holger krekel + +2.5.2 +----------------------------------- + +- fix issue409 -- better interoperate with cx_freeze by not + trying to import from collections.abc which causes problems + for py27/cx_freeze. Thanks Wolfgang L. for reporting and tracking it down. + +- fixed docs and code to use "pytest" instead of "py.test" almost everywhere. + Thanks Jurko Gospodnetic for the complete PR. + +- fix issue425: mention at end of "py.test -h" that --markers + and --fixtures work according to specified test path (or current dir) + +- fix issue413: exceptions with unicode attributes are now printed + correctly also on python2 and with pytest-xdist runs. (the fix + requires py-1.4.20) + +- copy, cleanup and integrate py.io capture + from pylib 1.4.20.dev2 (rev 13d9af95547e) + +- address issue416: clarify docs as to conftest.py loading semantics + +- fix issue429: comparing byte strings with non-ascii chars in assert + expressions now work better. Thanks Floris Bruynooghe. + +- make capfd/capsys.capture private, its unused and shouldnt be exposed + diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/assert.txt --- a/doc/en/assert.txt +++ b/doc/en/assert.txt @@ -26,19 +26,19 @@ $ py.test test_assert1.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 1 items - + test_assert1.py F - + ================================= FAILURES ================================= ______________________________ test_function _______________________________ - + def test_function(): > assert f() == 4 E assert 3 == 4 E + where 3 = f() - + test_assert1.py:5: AssertionError ========================= 1 failed in 0.01 seconds ========================= @@ -116,14 +116,14 @@ $ py.test test_assert2.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 1 items - + test_assert2.py F - + ================================= FAILURES ================================= ___________________________ test_set_comparison ____________________________ - + def test_set_comparison(): set1 = set("1308") set2 = set("8035") @@ -133,7 +133,7 @@ E '1' E Extra items in the right set: E '5' - + test_assert2.py:5: AssertionError ========================= 1 failed in 0.01 seconds ========================= diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/capture.txt --- a/doc/en/capture.txt +++ b/doc/en/capture.txt @@ -64,21 +64,21 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - + test_module.py .F - + ================================= FAILURES ================================= ________________________________ test_func2 ________________________________ - + def test_func2(): > assert False E assert False - + test_module.py:9: AssertionError ----------------------------- Captured stdout ------------------------------ - setting up + setting up ==================== 1 failed, 1 passed in 0.01 seconds ==================== Accessing captured output from a test function diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/conf.py --- a/doc/en/conf.py +++ b/doc/en/conf.py @@ -17,8 +17,8 @@ # # The full version, including alpha/beta/rc tags. # The short X.Y version. -version = "2.5.1" -release = "2.5.1" +version = "2.5.2" +release = "2.5.2" import sys, os diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/contents.txt --- a/doc/en/contents.txt +++ b/doc/en/contents.txt @@ -14,6 +14,7 @@ overview apiref plugins + plugins_index/index example/index talks contributing diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/doctest.txt --- a/doc/en/doctest.txt +++ b/doc/en/doctest.txt @@ -44,7 +44,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 1 items mymodule.py . diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/example/markers.txt --- a/doc/en/example/markers.txt +++ b/doc/en/example/markers.txt @@ -28,11 +28,11 @@ $ py.test -v -m webtest =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:3: test_send_http PASSED - + =================== 2 tests deselected by "-m 'webtest'" =================== ================== 1 passed, 2 deselected in 0.01 seconds ================== @@ -40,12 +40,12 @@ $ py.test -v -m "not webtest" =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:6: test_something_quick PASSED test_server.py:8: test_another PASSED - + ================= 1 tests deselected by "-m 'not webtest'" ================= ================== 2 passed, 1 deselected in 0.01 seconds ================== @@ -61,11 +61,11 @@ $ py.test -v -k http # running with the above defined example module =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:3: test_send_http PASSED - + ====================== 2 tests deselected by '-khttp' ====================== ================== 1 passed, 2 deselected in 0.01 seconds ================== @@ -73,12 +73,12 @@ $ py.test -k "not send_http" -v =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:6: test_something_quick PASSED test_server.py:8: test_another PASSED - + ================= 1 tests deselected by '-knot send_http' ================== ================== 2 passed, 1 deselected in 0.01 seconds ================== @@ -86,12 +86,12 @@ $ py.test -k "http or quick" -v =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items - + test_server.py:3: test_send_http PASSED test_server.py:6: test_something_quick PASSED - + ================= 1 tests deselected by '-khttp or quick' ================== ================== 2 passed, 1 deselected in 0.01 seconds ================== @@ -124,19 +124,19 @@ $ py.test --markers @pytest.mark.webtest: mark a test as a webtest. - + @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - + @pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html - + @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. - - @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures - + + @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures + @pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible. - + @pytest.mark.trylast: mark a hook implementation function such that the plugin machinery will try to call it last/as late as possible. - + For an example on how to add and work with markers from a plugin, see :ref:`adding a custom marker from a plugin`. @@ -266,41 +266,41 @@ $ py.test -E stage2 =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 1 items - + test_someenv.py s - + ======================== 1 skipped in 0.01 seconds ========================= and here is one that specifies exactly the environment needed:: $ py.test -E stage1 =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 1 items - + test_someenv.py . - + ========================= 1 passed in 0.01 seconds ========================= The ``--markers`` option always gives you a list of available markers:: $ py.test --markers @pytest.mark.env(name): mark test to run only on named environment - + @pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html - + @pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html - + @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. - - @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures - + + @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures + @pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible. - + @pytest.mark.trylast: mark a hook implementation function such that the plugin machinery will try to call it last/as late as possible. - + Reading markers which were set from multiple places ---------------------------------------------------- @@ -395,24 +395,24 @@ $ py.test -rs # this option reports skip reasons =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 4 items - + test_plat.py s.s. ========================= short test summary info ========================== - SKIP [2] /tmp/doc-exec-63/conftest.py:12: cannot run on platform linux2 - + SKIP [2] /tmp/doc-exec-65/conftest.py:12: cannot run on platform linux2 + =================== 2 passed, 2 skipped in 0.01 seconds ==================== Note that if you specify a platform via the marker-command line option like this:: $ py.test -m linux2 =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 4 items - + test_plat.py . - + =================== 3 tests deselected by "-m 'linux2'" ==================== ================== 1 passed, 3 deselected in 0.01 seconds ================== @@ -459,11 +459,11 @@ $ py.test -m interface --tb=short =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 4 items - + test_module.py FF - + ================================= FAILURES ================================= __________________________ test_interface_simple ___________________________ test_module.py:3: in test_interface_simple @@ -480,11 +480,11 @@ $ py.test -m "interface or event" --tb=short =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 4 items - + test_module.py FFF - + ================================= FAILURES ================================= __________________________ test_interface_simple ___________________________ test_module.py:3: in test_interface_simple diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/example/nonpython.txt --- a/doc/en/example/nonpython.txt +++ b/doc/en/example/nonpython.txt @@ -27,10 +27,10 @@ nonpython $ py.test test_simple.yml =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - test_simple.yml .F + test_simple.yml F. ================================= FAILURES ================================= ______________________________ usecase: hello ______________________________ @@ -56,11 +56,11 @@ nonpython $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 2 items + test_simple.yml:1: usecase: hello FAILED test_simple.yml:1: usecase: ok PASSED - test_simple.yml:1: usecase: hello FAILED ================================= FAILURES ================================= ______________________________ usecase: hello ______________________________ @@ -74,10 +74,10 @@ nonpython $ py.test --collect-only =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items + - ============================= in 0.02 seconds ============================= diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/example/parametrize.txt --- a/doc/en/example/parametrize.txt +++ b/doc/en/example/parametrize.txt @@ -106,11 +106,11 @@ $ py.test test_scenarios.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 4 items - + test_scenarios.py .... - + ========================= 4 passed in 0.01 seconds ========================= If you just collect tests you'll also nicely see 'advanced' and 'basic' as variants for the test function:: @@ -118,7 +118,7 @@ $ py.test --collect-only test_scenarios.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 4 items @@ -127,7 +127,7 @@ - + ============================= in 0.01 seconds ============================= Note that we told ``metafunc.parametrize()`` that your scenario values @@ -182,12 +182,12 @@ $ py.test test_backends.py --collect-only =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - + ============================= in 0.00 seconds ============================= And then when we run the test:: @@ -196,15 +196,15 @@ .F ================================= FAILURES ================================= _________________________ test_db_initialized[d2] __________________________ - - db = - + + db = + def test_db_initialized(db): # a dummy test if db.__class__.__name__ == "DB2": > pytest.fail("deliberately failing for demo purposes") E Failed: deliberately failing for demo purposes - + test_backends.py:6: Failed 1 failed, 1 passed in 0.01 seconds @@ -251,14 +251,14 @@ $ py.test -q F.. ================================= FAILURES ================================= - ________________________ TestClass.test_equals[2-1] ________________________ - - self = , a = 1, b = 2 - + ________________________ TestClass.test_equals[1-2] ________________________ + + self = , a = 1, b = 2 + def test_equals(self, a, b): > assert a == b E assert 1 == 2 - + test_parametrize.py:18: AssertionError 1 failed, 2 passed in 0.01 seconds @@ -281,8 +281,8 @@ . $ py.test -rs -q multipython.py ............sss............sss............sss............ssssssssssssssssss ========================= short test summary info ========================== - SKIP [27] /home/hpk/p/pytest/doc/en/example/multipython.py:21: 'python2.8' not found - 48 passed, 27 skipped in 1.34 seconds + SKIP [27] /home/hpk/p/pytest/doc/en/example/multipython.py:22: 'python2.8' not found + 48 passed, 27 skipped in 1.30 seconds Indirect parametrization of optional implementations/imports -------------------------------------------------------------------- @@ -329,13 +329,13 @@ $ py.test -rs test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - + test_module.py .s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-65/conftest.py:10: could not import 'opt2' - + SKIP [1] /tmp/doc-exec-67/conftest.py:10: could not import 'opt2' + =================== 1 passed, 1 skipped in 0.01 seconds ==================== You'll see that we don't have a ``opt2`` module and thus the second test run diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/example/pythoncollection.txt --- a/doc/en/example/pythoncollection.txt +++ b/doc/en/example/pythoncollection.txt @@ -43,14 +43,14 @@ $ py.test --collect-only =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - + ============================= in 0.01 seconds ============================= .. note:: @@ -88,7 +88,7 @@ . $ py.test --collect-only pythoncollection.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 3 items @@ -96,7 +96,7 @@ - + ============================= in 0.01 seconds ============================= customizing test collection to find all .py files @@ -141,11 +141,11 @@ $ py.test --collect-only =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 1 items - + ============================= in 0.01 seconds ============================= If you run with a Python3 interpreter the moduled added through the conftest.py file will not be considered for test collection. diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/example/reportingdemo.txt --- a/doc/en/example/reportingdemo.txt +++ b/doc/en/example/reportingdemo.txt @@ -13,84 +13,84 @@ assertion $ py.test failure_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 39 items - + failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - + ================================= FAILURES ================================= ____________________________ test_generative[0] ____________________________ - + param1 = 3, param2 = 6 - + def test_generative(param1, param2): > assert param1 * 2 < param2 E assert (3 * 2) < 6 - + failure_demo.py:15: AssertionError _________________________ TestFailing.test_simple __________________________ - - self = - + + self = + def test_simple(self): def f(): return 42 def g(): return 43 - + > assert f() == g() E assert 42 == 43 - E + where 42 = () - E + and 43 = () - + E + where 42 = () + E + and 43 = () + failure_demo.py:28: AssertionError ____________________ TestFailing.test_simple_multiline _____________________ - - self = - + + self = + def test_simple_multiline(self): otherfunc_multi( 42, > 6*9) - - failure_demo.py:33: - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - + + failure_demo.py:33: + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + a = 42, b = 54 - + def otherfunc_multi(a,b): > assert (a == b) E assert 42 == 54 - + failure_demo.py:11: AssertionError ___________________________ TestFailing.test_not ___________________________ - - self = - + + self = + def test_not(self): def f(): return 42 > assert not f() E assert not 42 - E + where 42 = () - + E + where 42 = () + failure_demo.py:38: AssertionError _________________ TestSpecialisedExplanations.test_eq_text _________________ - - self = - + + self = + def test_eq_text(self): > assert 'spam' == 'eggs' E assert 'spam' == 'eggs' E - spam E + eggs - + failure_demo.py:42: AssertionError _____________ TestSpecialisedExplanations.test_eq_similar_text _____________ - - self = - + + self = + def test_eq_similar_text(self): > assert 'foo 1 bar' == 'foo 2 bar' E assert 'foo 1 bar' == 'foo 2 bar' @@ -98,12 +98,12 @@ E ? ^ E + foo 2 bar E ? ^ - + failure_demo.py:45: AssertionError ____________ TestSpecialisedExplanations.test_eq_multiline_text ____________ - - self = - + + self = + def test_eq_multiline_text(self): > assert 'foo\nspam\nbar' == 'foo\neggs\nbar' E assert 'foo\nspam\nbar' == 'foo\neggs\nbar' @@ -111,12 +111,12 @@ E - spam E + eggs E bar - + failure_demo.py:48: AssertionError ______________ TestSpecialisedExplanations.test_eq_long_text _______________ - - self = - + + self = + def test_eq_long_text(self): a = '1'*100 + 'a' + '2'*100 b = '1'*100 + 'b' + '2'*100 @@ -128,12 +128,12 @@ E ? ^ E + 1111111111b222222222 E ? ^ - + failure_demo.py:53: AssertionError _________ TestSpecialisedExplanations.test_eq_long_text_multiline __________ - - self = - + + self = + def test_eq_long_text_multiline(self): a = '1\n'*100 + 'a' + '2\n'*100 b = '1\n'*100 + 'b' + '2\n'*100 @@ -152,34 +152,34 @@ E 2 E 2 E 2 - + failure_demo.py:58: AssertionError _________________ TestSpecialisedExplanations.test_eq_list _________________ - - self = - + + self = + def test_eq_list(self): > assert [0, 1, 2] == [0, 1, 3] E assert [0, 1, 2] == [0, 1, 3] E At index 2 diff: 2 != 3 - + failure_demo.py:61: AssertionError ______________ TestSpecialisedExplanations.test_eq_list_long _______________ - - self = - + + self = + def test_eq_list_long(self): a = [0]*100 + [1] + [3]*100 b = [0]*100 + [2] + [3]*100 > assert a == b E assert [0, 0, 0, 0, 0, 0, ...] == [0, 0, 0, 0, 0, 0, ...] E At index 100 diff: 1 != 2 - + failure_demo.py:66: AssertionError _________________ TestSpecialisedExplanations.test_eq_dict _________________ - - self = - + + self = + def test_eq_dict(self): > assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} E assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} @@ -190,12 +190,12 @@ E {'c': 0} E Right contains more items: E {'d': 0} - + failure_demo.py:69: AssertionError _________________ TestSpecialisedExplanations.test_eq_set __________________ - - self = - + + self = + def test_eq_set(self): > assert set([0, 10, 11, 12]) == set([0, 20, 21]) E assert set([0, 10, 11, 12]) == set([0, 20, 21]) @@ -206,31 +206,31 @@ E Extra items in the right set: E 20 E 21 - + failure_demo.py:72: AssertionError _____________ TestSpecialisedExplanations.test_eq_longer_list ______________ - - self = - + + self = + def test_eq_longer_list(self): > assert [1,2] == [1,2,3] E assert [1, 2] == [1, 2, 3] E Right contains more items, first extra item: 3 - + failure_demo.py:75: AssertionError _________________ TestSpecialisedExplanations.test_in_list _________________ - - self = - + + self = + def test_in_list(self): > assert 1 in [0, 2, 3, 4, 5] E assert 1 in [0, 2, 3, 4, 5] - + failure_demo.py:78: AssertionError __________ TestSpecialisedExplanations.test_not_in_text_multiline __________ - - self = - + + self = + def test_not_in_text_multiline(self): text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail' > assert 'foo' not in text @@ -243,12 +243,12 @@ E ? +++ E and a E tail - + failure_demo.py:82: AssertionError ___________ TestSpecialisedExplanations.test_not_in_text_single ____________ - - self = - + + self = + def test_not_in_text_single(self): text = 'single foo line' > assert 'foo' not in text @@ -256,58 +256,58 @@ E 'foo' is contained here: E single foo line E ? +++ - + failure_demo.py:86: AssertionError _________ TestSpecialisedExplanations.test_not_in_text_single_long _________ - - self = - + + self = + def test_not_in_text_single_long(self): text = 'head ' * 50 + 'foo ' + 'tail ' * 20 > assert 'foo' not in text E assert 'foo' not in 'head head head head hea...ail tail tail tail tail ' E 'foo' is contained here: - E head head foo tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail + E head head foo tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail E ? +++ - + failure_demo.py:90: AssertionError ______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______ - - self = - + + self = + def test_not_in_text_single_long_term(self): text = 'head ' * 50 + 'f'*70 + 'tail ' * 20 > assert 'f'*70 not in text E assert 'fffffffffff...ffffffffffff' not in 'head head he...l tail tail ' E 'ffffffffffffffffff...fffffffffffffffffff' is contained here: - E head head fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffftail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail + E head head fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffftail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail E ? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - + failure_demo.py:94: AssertionError ______________________________ test_attribute ______________________________ - + def test_attribute(): class Foo(object): b = 1 i = Foo() > assert i.b == 2 E assert 1 == 2 - E + where 1 = .b - + E + where 1 = .b + failure_demo.py:101: AssertionError _________________________ test_attribute_instance __________________________ - + def test_attribute_instance(): class Foo(object): b = 1 > assert Foo().b == 2 E assert 1 == 2 - E + where 1 = .b - E + where = () - + E + where 1 = .b + E + where = () + failure_demo.py:107: AssertionError __________________________ test_attribute_failure __________________________ - + def test_attribute_failure(): class Foo(object): def _get_b(self): @@ -315,19 +315,19 @@ b = property(_get_b) i = Foo() > assert i.b == 2 - - failure_demo.py:116: - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - - self = - + + failure_demo.py:116: + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + + self = + def _get_b(self): > raise Exception('Failed to get attrib') E Exception: Failed to get attrib - + failure_demo.py:113: Exception _________________________ test_attribute_multiple __________________________ - + def test_attribute_multiple(): class Foo(object): b = 1 @@ -335,78 +335,78 @@ b = 2 > assert Foo().b == Bar().b E assert 1 == 2 - E + where 1 = .b - E + where = () - E + and 2 = .b - E + where = () - + E + where 1 = .b + E + where = () + E + and 2 = .b + E + where = () + failure_demo.py:124: AssertionError __________________________ TestRaises.test_raises __________________________ - - self = - + + self = + def test_raises(self): s = 'qwe' > raises(TypeError, "int(s)") - - failure_demo.py:133: - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - + + failure_demo.py:133: + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - - <0-codegen /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:983>:1: ValueError + + <0-codegen /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:999>:1: ValueError ______________________ TestRaises.test_raises_doesnt _______________________ - - self = - + + self = + def test_raises_doesnt(self): > raises(IOError, "int('3')") E Failed: DID NOT RAISE - + failure_demo.py:136: Failed __________________________ TestRaises.test_raise ___________________________ - - self = - + + self = + def test_raise(self): > raise ValueError("demo error") E ValueError: demo error - + failure_demo.py:139: ValueError ________________________ TestRaises.test_tupleerror ________________________ - - self = - + + self = + def test_tupleerror(self): > a,b = [1] E ValueError: need more than 1 value to unpack - + failure_demo.py:142: ValueError ______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______ - - self = - + + self = + def test_reinterpret_fails_with_print_for_the_fun_of_it(self): l = [1,2,3] print ("l is %r" % l) > a,b = l.pop() E TypeError: 'int' object is not iterable - + failure_demo.py:147: TypeError ----------------------------- Captured stdout ------------------------------ l is [1, 2, 3] ________________________ TestRaises.test_some_error ________________________ - - self = - + + self = + def test_some_error(self): > if namenotexi: E NameError: global name 'namenotexi' is not defined - + failure_demo.py:150: NameError ____________________ test_dynamic_compile_shows_nicely _____________________ - + def test_dynamic_compile_shows_nicely(): src = 'def foo():\n assert 1 == 0\n' name = 'abc-123' @@ -415,132 +415,132 @@ py.builtin.exec_(code, module.__dict__) py.std.sys.modules[name] = module > module.foo() - - failure_demo.py:165: - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - + + failure_demo.py:165: + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + def foo(): > assert 1 == 0 E assert 1 == 0 - + <2-codegen 'abc-123' /home/hpk/p/pytest/doc/en/example/assertion/failure_demo.py:162>:2: AssertionError ____________________ TestMoreErrors.test_complex_error _____________________ - - self = - + + self = + def test_complex_error(self): def f(): return 44 def g(): return 43 > somefunc(f(), g()) - - failure_demo.py:175: - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - + + failure_demo.py:175: + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + x = 44, y = 43 - + def somefunc(x,y): > otherfunc(x,y) - - failure_demo.py:8: - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - + + failure_demo.py:8: + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + a = 44, b = 43 - + def otherfunc(a,b): > assert a==b E assert 44 == 43 - + failure_demo.py:5: AssertionError ___________________ TestMoreErrors.test_z1_unpack_error ____________________ - - self = - + + self = + def test_z1_unpack_error(self): l = [] > a,b = l E ValueError: need more than 0 values to unpack - + failure_demo.py:179: ValueError ____________________ TestMoreErrors.test_z2_type_error _____________________ - - self = - + + self = + def test_z2_type_error(self): l = 3 > a,b = l E TypeError: 'int' object is not iterable - + failure_demo.py:183: TypeError ______________________ TestMoreErrors.test_startswith ______________________ - - self = - + + self = + def test_startswith(self): s = "123" g = "456" > assert s.startswith(g) - E assert ('456') - E + where = '123'.startswith - + E assert ('456') + E + where = '123'.startswith + failure_demo.py:188: AssertionError __________________ TestMoreErrors.test_startswith_nested ___________________ - - self = - + + self = + def test_startswith_nested(self): def f(): return "123" def g(): return "456" > assert f().startswith(g()) - E assert ('456') - E + where = '123'.startswith - E + where '123' = () - E + and '456' = () - + E assert ('456') + E + where = '123'.startswith + E + where '123' = () + E + and '456' = () + failure_demo.py:195: AssertionError _____________________ TestMoreErrors.test_global_func ______________________ - - self = - + + self = + def test_global_func(self): > assert isinstance(globf(42), float) E assert isinstance(43, float) E + where 43 = globf(42) - + failure_demo.py:198: AssertionError _______________________ TestMoreErrors.test_instance _______________________ - - self = - + + self = + def test_instance(self): self.x = 6*7 > assert self.x != 42 E assert 42 != 42 - E + where 42 = .x - + E + where 42 = .x + failure_demo.py:202: AssertionError _______________________ TestMoreErrors.test_compare ________________________ - - self = - + + self = + def test_compare(self): > assert globf(10) < 5 E assert 11 < 5 E + where 11 = globf(10) - + failure_demo.py:205: AssertionError _____________________ TestMoreErrors.test_try_finally ______________________ - - self = - + + self = + def test_try_finally(self): x = 1 try: > assert x == 0 E assert 1 == 0 - + failure_demo.py:210: AssertionError ======================== 39 failed in 0.20 seconds ========================= diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/example/simple.txt --- a/doc/en/example/simple.txt +++ b/doc/en/example/simple.txt @@ -108,9 +108,9 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 0 items - + ============================= in 0.00 seconds ============================= .. _`excontrolskip`: @@ -152,24 +152,24 @@ $ py.test -rs # "-rs" means report details on the little 's' =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - + test_module.py .s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-68/conftest.py:9: need --runslow option to run - + SKIP [1] /tmp/doc-exec-70/conftest.py:9: need --runslow option to run + =================== 1 passed, 1 skipped in 0.01 seconds ==================== Or run it including the ``slow`` marked test:: $ py.test --runslow =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - + test_module.py .. - + ========================= 2 passed in 0.01 seconds ========================= Writing well integrated assertion helpers @@ -256,10 +256,10 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 project deps: mylib-1.1 collected 0 items - + ============================= in 0.00 seconds ============================= .. regendoc:wipe @@ -279,20 +279,20 @@ $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python info1: did you know that ... did you? collecting ... collected 0 items - + ============================= in 0.00 seconds ============================= and nothing when run plainly:: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 0 items - + ============================= in 0.00 seconds ============================= profiling test duration @@ -322,11 +322,11 @@ $ py.test --durations=3 =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 3 items - + test_some_are_slow.py ... - + ========================= slowest 3 test durations ========================= 0.20s call test_some_are_slow.py::test_funcslow2 0.10s call test_some_are_slow.py::test_funcslow1 @@ -383,20 +383,20 @@ $ py.test -rx =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 4 items - + test_step.py .Fx. - + ================================= FAILURES ================================= ____________________ TestUserHandling.test_modification ____________________ - - self = - + + self = + def test_modification(self): > assert 0 E assert 0 - + test_step.py:9: AssertionError ========================= short test summary info ========================== XFAIL test_step.py::TestUserHandling::()::test_deletion @@ -453,50 +453,50 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 7 items - + test_step.py .Fx. a/test_db.py F a/test_db2.py F b/test_error.py E - + ================================== ERRORS ================================== _______________________ ERROR at setup of test_root ________________________ - file /tmp/doc-exec-68/b/test_error.py, line 1 + file /tmp/doc-exec-70/b/test_error.py, line 1 def test_root(db): # no db here, will error out fixture 'db' not found - available fixtures: recwarn, capfd, pytestconfig, capsys, tmpdir, monkeypatch + available fixtures: pytestconfig, capfd, monkeypatch, capsys, recwarn, tmpdir use 'py.test --fixtures [testpath]' for help on them. - - /tmp/doc-exec-68/b/test_error.py:1 + + /tmp/doc-exec-70/b/test_error.py:1 ================================= FAILURES ================================= ____________________ TestUserHandling.test_modification ____________________ - - self = - + + self = + def test_modification(self): > assert 0 E assert 0 - + test_step.py:9: AssertionError _________________________________ test_a1 __________________________________ - - db = - + + db = + def test_a1(db): > assert 0, db # to show value - E AssertionError: - + E AssertionError: + a/test_db.py:2: AssertionError _________________________________ test_a2 __________________________________ - - db = - + + db = + def test_a2(db): > assert 0, db # to show value - E AssertionError: - + E AssertionError: + a/test_db2.py:2: AssertionError ========== 3 failed, 2 passed, 1 xfailed, 1 error in 0.03 seconds ========== @@ -553,34 +553,34 @@ $ py.test test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - + test_module.py FF - + ================================= FAILURES ================================= ________________________________ test_fail1 ________________________________ - - tmpdir = local('/tmp/pytest-42/test_fail10') - + + tmpdir = local('/tmp/pytest-1012/test_fail10') + def test_fail1(tmpdir): > assert 0 E assert 0 - + test_module.py:2: AssertionError ________________________________ test_fail2 ________________________________ - + def test_fail2(): > assert 0 E assert 0 - + test_module.py:4: AssertionError ========================= 2 failed in 0.01 seconds ========================= you will have a "failures" file which contains the failing test ids:: $ cat failures - test_module.py::test_fail1 (/tmp/pytest-42/test_fail10) + test_module.py::test_fail1 (/tmp/pytest-1012/test_fail10) test_module.py::test_fail2 Making test result information available in fixtures @@ -643,38 +643,38 @@ $ py.test -s test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 3 items - + test_module.py Esetting up a test failed! test_module.py::test_setup_fails Fexecuting test failed test_module.py::test_call_fails F - + ================================== ERRORS ================================== ____________________ ERROR at setup of test_setup_fails ____________________ - + @pytest.fixture def other(): > assert 0 E assert 0 - + test_module.py:6: AssertionError ================================= FAILURES ================================= _____________________________ test_call_fails ______________________________ - + something = None - + def test_call_fails(something): > assert 0 E assert 0 - + test_module.py:12: AssertionError ________________________________ test_fail2 ________________________________ - + def test_fail2(): > assert 0 E assert 0 - + test_module.py:15: AssertionError ==================== 2 failed, 1 error in 0.01 seconds ===================== diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/fixture.txt --- a/doc/en/fixture.txt +++ b/doc/en/fixture.txt @@ -76,23 +76,23 @@ $ py.test test_smtpsimple.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 1 items - + test_smtpsimple.py F - + ================================= FAILURES ================================= ________________________________ test_ehlo _________________________________ - - smtp = - + + smtp = + def test_ehlo(smtp): response, msg = smtp.ehlo() assert response == 250 assert "merlinux" in msg > assert 0 # for demo purposes E assert 0 - + test_smtpsimple.py:12: AssertionError ========================= 1 failed in 0.21 seconds ========================= @@ -194,36 +194,36 @@ $ py.test test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 2 items - + test_module.py FF - + ================================= FAILURES ================================= ________________________________ test_ehlo _________________________________ - - smtp = - + + smtp = + def test_ehlo(smtp): response = smtp.ehlo() assert response[0] == 250 assert "merlinux" in response[1] > assert 0 # for demo purposes E assert 0 - + test_module.py:6: AssertionError ________________________________ test_noop _________________________________ - - smtp = - + + smtp = + def test_noop(smtp): response = smtp.noop() assert response[0] == 250 > assert 0 # for demo purposes E assert 0 - + test_module.py:11: AssertionError - ========================= 2 failed in 0.17 seconds ========================= + ========================= 2 failed in 0.23 seconds ========================= You see the two ``assert 0`` failing and more importantly you can also see that the same (module-scoped) ``smtp`` object was passed into the two @@ -270,8 +270,8 @@ $ py.test -s -q --tb=no FFteardown smtp - - 2 failed in 0.17 seconds + + 2 failed in 0.21 seconds We see that the ``smtp`` instance is finalized after the two tests finished execution. Note that if we decorated our fixture @@ -312,7 +312,7 @@ $ py.test -s -q --tb=no FF - 2 failed in 0.21 seconds + 2 failed in 0.59 seconds Let's quickly create another test module that actually sets the server URL in its module namespace:: @@ -378,53 +378,53 @@ FFFF ================================= FAILURES ================================= __________________________ test_ehlo[merlinux.eu] __________________________ - - smtp = - + + smtp = + def test_ehlo(smtp): response = smtp.ehlo() assert response[0] == 250 assert "merlinux" in response[1] > assert 0 # for demo purposes E assert 0 - + test_module.py:6: AssertionError __________________________ test_noop[merlinux.eu] __________________________ - - smtp = - + + smtp = + def test_noop(smtp): response = smtp.noop() assert response[0] == 250 > assert 0 # for demo purposes E assert 0 - + test_module.py:11: AssertionError ________________________ test_ehlo[mail.python.org] ________________________ - - smtp = - + + smtp = + def test_ehlo(smtp): response = smtp.ehlo() assert response[0] == 250 > assert "merlinux" in response[1] E assert 'merlinux' in 'mail.python.org\nSIZE 25600000\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME\nDSN' - + test_module.py:5: AssertionError ----------------------------- Captured stdout ------------------------------ - finalizing + finalizing ________________________ test_noop[mail.python.org] ________________________ - - smtp = - + + smtp = + def test_noop(smtp): response = smtp.noop() assert response[0] == 250 > assert 0 # for demo purposes E assert 0 - + test_module.py:11: AssertionError - 4 failed in 6.58 seconds + 4 failed in 6.06 seconds We see that our two test functions each ran twice, against the different ``smtp`` instances. Note also, that with the ``mail.python.org`` @@ -464,13 +464,13 @@ $ py.test -v test_appsetup.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 2 items - + test_appsetup.py:12: test_smtp_exists[merlinux.eu] PASSED test_appsetup.py:12: test_smtp_exists[mail.python.org] PASSED - - ========================= 2 passed in 5.95 seconds ========================= + + ========================= 2 passed in 6.42 seconds ========================= Due to the parametrization of ``smtp`` the test will run twice with two different ``App`` instances and respective smtp servers. There is no @@ -528,9 +528,9 @@ $ py.test -v -s test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 8 items - + test_module.py:15: test_0[1] test0 1 PASSED test_module.py:15: test_0[2] test0 2 @@ -549,7 +549,7 @@ PASSED test_module.py:19: test_2[2-mod2] test2 2 mod2 PASSED - + ========================= 8 passed in 0.01 seconds ========================= You can see that the parametrized module-scoped ``modarg`` resource caused diff -r fbc05fb4bc715877eda0d733d69f025c7adc0db9 -r 1a190672b6cc3803f43d24bfe9a106df96a47629 doc/en/getting-started.txt --- a/doc/en/getting-started.txt +++ b/doc/en/getting-started.txt @@ -23,7 +23,7 @@ To check your installation has installed the correct version:: $ py.test --version - This is pytest version 2.5.1, imported from /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/pytest.pyc + This is pytest version 2.5.2, imported from /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/pytest.pyc If you get an error checkout :ref:`installation issues`. @@ -45,19 +45,19 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.5.1 + platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 collected 1 items - + test_sample.py F - + ================================= FAILURES ================================= _______________________________ test_answer ________________________________ - + def test_answer(): > assert func(3) == 5 E assert 4 == 5 E + where 4 = func(3) - + test_sample.py:5: AssertionError ========================= 1 failed in 0.01 seconds ========================= @@ -93,7 +93,7 @@ $ py.test -q test_sysexit.py . - 1 passed in 0.00 seconds + 1 passed in 0.01 seconds .. todo:: For further ways to assert exceptions see the `raises` @@ -122,14 +122,14 @@ .F ================================= FAILURES ================================= ____________________________ TestClass.test_two ____________________________ - - self = - + + self = + def test_two(self): x = "hello" > assert hasattr(x, 'check') E assert hasattr('hello', 'check') - + test_class.py:8: AssertionError 1 failed, 1 passed in 0.01 seconds @@ -158,18 +158,18 @@ F ================================= FAILURES ================================= _____________________________ test_needsfiles ______________________________ - - tmpdir = local('/tmp/pytest-38/test_needsfiles0') - + + tmpdir = local('/tmp/pytest-1008/test_needsfiles0') + def test_needsfiles(tmpdir): print tmpdir > assert 0 E assert 0 - + test_tmpdir.py:3: AssertionError ----------------------------- Captured stdout ------------------------------ - /tmp/pytest-38/test_needsfiles0 - 1 failed in 0.04 seconds + /tmp/pytest-1008/test_needsfiles0 + 1 failed in 0.01 seconds Before the test runs, a unique-per-test-invocation temporary directory was created. More info at :ref:`tmpdir handling`. This diff is so big that we needed to truncate the remainder. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 29 13:58:56 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 29 Jan 2014 12:58:56 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: make it clear that this xfail is an unimplemented feature, nothing more. Message-ID: <20140129125856.7834.99717@app18.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/421d3b4d150d/ Changeset: 421d3b4d150d User: hpk42 Date: 2014-01-29 13:56:24 Summary: make it clear that this xfail is an unimplemented feature, nothing more. Affected #: 1 file diff -r 1a190672b6cc3803f43d24bfe9a106df96a47629 -r 421d3b4d150d901de24b1cbeb8955547b1420483 testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -191,7 +191,7 @@ "in func2*", ]) - @pytest.mark.xfail + @pytest.mark.xfail(reason="unimplemented feature") def test_capture_scope_cache(self, testdir): p = testdir.makepyfile(""" import sys Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 29 14:09:40 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 29 Jan 2014 13:09:40 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: Added tag 2.5.2 for changeset 421d3b4d150d Message-ID: <20140129130940.3445.76631@app06.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/cba8287569b0/ Changeset: cba8287569b0 User: hpk42 Date: 2014-01-29 14:09:33 Summary: Added tag 2.5.2 for changeset 421d3b4d150d Affected #: 1 file diff -r 421d3b4d150d901de24b1cbeb8955547b1420483 -r cba8287569b0e19d15436e2310b832b9315d0c84 .hgtags --- a/.hgtags +++ b/.hgtags @@ -65,3 +65,4 @@ 8d051f89184bfa3033f5e59819dff9f32a612941 2.4.2 a064ad64d167508a8e9e73766b1a4e6bd10c85db 2.5.0 039d543d1ca02a716c0b0de9a7131beb8021e8a2 2.5.1 +421d3b4d150d901de24b1cbeb8955547b1420483 2.5.2 Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 29 14:24:43 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 29 Jan 2014 13:24:43 -0000 Subject: [Pytest-commit] commit/tox: 3 new changesets Message-ID: <20140129132443.4018.32239@app09.ash-private.bitbucket.org> 3 new commits in tox: https://bitbucket.org/hpk42/tox/commits/5b4e536b8d38/ Changeset: 5b4e536b8d38 User: hpk42 Date: 2014-01-29 14:03:13 Summary: try to go for 1.7.0 Affected #: 5 files diff -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d -r 5b4e536b8d3810c791b742b2a8723c53b8d3d720 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -1.7.0.dev +1.7.0 --------- - don't lookup "pip-script" anymore but rather just "pip" on windows @@ -27,7 +27,7 @@ to allow installation of tox via easy_install/eggs. Thanks Jenisys. -- fix issue126: depend on virtualenv>=1.11.1 so that we can rely +- fix issue126: depend on virtualenv>=1.11.2 so that we can rely (hopefully) on a pip version which supports --pre. (tox by default uses to --pre). also merged in PR84 so that we now call "virtualenv" directly instead of looking up interpreters. Thanks Ionel Maries Cristian. diff -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d -r 5b4e536b8d3810c791b742b2a8723c53b8d3d720 README.rst --- a/README.rst +++ b/README.rst @@ -21,5 +21,5 @@ have fun, -holger krekel, May 2013 +holger krekel, January 2014 diff -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d -r 5b4e536b8d3810c791b742b2a8723c53b8d3d720 setup.py --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ def main(): version = sys.version_info[:2] - install_requires = ['virtualenv>=1.11.1', 'py>=1.4.17', ] + install_requires = ['virtualenv>=1.11.2', 'py>=1.4.17', ] if version < (2, 7) or (3, 0) <= version <= (3, 1): install_requires += ['argparse'] if version < (2,6): @@ -28,7 +28,7 @@ description='virtualenv-based automation of test activities', long_description=open("README.rst").read(), url='http://tox.testrun.org/', - version='1.7.0.dev2', + version='1.7.0', license='http://opensource.org/licenses/MIT', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', diff -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d -r 5b4e536b8d3810c791b742b2a8723c53b8d3d720 tox.ini --- a/tox.ini +++ b/tox.ini @@ -8,11 +8,6 @@ commands=py.test --junitxml={envlogdir}/junit-{envname}.xml {posargs} deps=pytest>=2.3.5 -[testenv:x] -setenv= - HELLO=echo hello world -commands={env:HELLO} - [testenv:docs] basepython=python changedir=doc diff -r 9dce275b9bbd42dc09a262ac0c45f1ada2d9910d -r 5b4e536b8d3810c791b742b2a8723c53b8d3d720 tox/__init__.py --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '1.7.0.dev2' +__version__ = '1.7.0' class exception: class Error(Exception): https://bitbucket.org/hpk42/tox/commits/4e5c8cea6e24/ Changeset: 4e5c8cea6e24 User: hpk42 Date: 2014-01-29 14:23:23 Summary: Added tag 1.7.0 for changeset 5b4e536b8d38 Affected #: 1 file diff -r 5b4e536b8d3810c791b742b2a8723c53b8d3d720 -r 4e5c8cea6e2434e9ae1a0b624422361adf9b2f35 .hgtags --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ 8fcc1bed3e918b625d85864cc3f4623578852e7e 1.5.0 33e5e5dff406e699893a65ecd5044d3eee35b69b 1.6.0 2e580ee6feea934cc2e683635abded27c0de0be9 1.6.1 +5b4e536b8d3810c791b742b2a8723c53b8d3d720 1.7.0 https://bitbucket.org/hpk42/tox/commits/b0360a54ab36/ Changeset: b0360a54ab36 User: hpk42 Date: 2014-01-29 14:24:11 Summary: fix doc version Affected #: 1 file diff -r 4e5c8cea6e2434e9ae1a0b624422361adf9b2f35 -r b0360a54ab368ef428c7f83601ba6b64f6fec64f doc/conf.py --- a/doc/conf.py +++ b/doc/conf.py @@ -48,7 +48,7 @@ # built documents. # # The short X.Y version. -release = version = "1.6.1" +release = version = "1.7.0" # The full version, including alpha/beta/rc tags. # The language for content autogenerated by Sphinx. Refer to documentation Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Jan 29 14:28:37 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 29 Jan 2014 13:28:37 -0000 Subject: [Pytest-commit] commit/pytest-xdist: 3 new changesets Message-ID: <20140129132837.7952.49127@app12.ash-private.bitbucket.org> 3 new commits in pytest-xdist: https://bitbucket.org/hpk42/pytest-xdist/commits/bd6929909d33/ Changeset: bd6929909d33 User: hpk42 Date: 2014-01-27 19:47:37 Summary: make pexpect specific environments so that the canonical ones also run on windows. Also add a little sleep to a pexpect-related tests in the hope it helps the test consistently passing (Bah). Affected #: 2 files diff -r 5be06b2a6411b5ac468556932861c01b21bbb107 -r bd6929909d3330d6042fbe2f85be1ce9957bc922 testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -256,6 +256,7 @@ time.sleep(10) """) child = testdir.spawn_pytest("-n1") + py.std.time.sleep(0.1) child.expect(".*test session starts.*") child.kill(2) # keyboard interrupt child.expect(".*KeyboardInterrupt.*") diff -r 5be06b2a6411b5ac468556932861c01b21bbb107 -r bd6929909d3330d6042fbe2f85be1ce9957bc922 tox.ini --- a/tox.ini +++ b/tox.ini @@ -1,25 +1,26 @@ [tox] -envlist=py26,py32,py33,py27,py26,py26-old,py33-old +envlist=py26,py32,py33,py27,py27-pexpect,py33-pexpect,py26,py26-old,py33-old [testenv] changedir=testing deps=pytest>=2.5.1 commands= py.test --junitxml={envlogdir}/junit-{envname}.xml [] -[testenv:py27] -deps= - pytest>=2.4.2 +[testenv:py27-pexpect] +deps={[testenv]deps} + pexpect +[testenv:py33-pexpect] +deps={[testenv]deps} pexpect [testenv:py26-old] deps= - pytest==2.3.5 - pexpect + pytest==2.4.2 [testenv:py33-old] basepython = python3.3 deps= - pytest==2.3.5 + pytest==2.4.2 [pytest] addopts = -rsfxX https://bitbucket.org/hpk42/pytest-xdist/commits/4406fc2a6427/ Changeset: 4406fc2a6427 User: hpk42 Date: 2014-01-29 13:10:20 Summary: final Affected #: 1 file diff -r bd6929909d3330d6042fbe2f85be1ce9957bc922 -r 4406fc2a6427fadc021ed7e43e7aa5032b1ea91f CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -1.10 unreleased +1.10 ------------------------- - add glob support for rsyncignores, add command line option to pass https://bitbucket.org/hpk42/pytest-xdist/commits/b47ddaa7cc6c/ Changeset: b47ddaa7cc6c User: hpk42 Date: 2014-01-29 14:28:31 Summary: Added tag 1.10 for changeset 4406fc2a6427 Affected #: 1 file diff -r 4406fc2a6427fadc021ed7e43e7aa5032b1ea91f -r b47ddaa7cc6ceb0345895db32f65861d450982f9 .hgtags --- a/.hgtags +++ b/.hgtags @@ -14,3 +14,4 @@ 0d1c00018008433956aa7d93007bab6ea7de96e4 1.8 1d27987c267577899350a25ba5828d55d87083ad 1.8 5c5cb6d59e12e566fbb0217aea718dc31578bee1 1.9 +4406fc2a6427fadc021ed7e43e7aa5032b1ea91f 1.10 Repository URL: https://bitbucket.org/hpk42/pytest-xdist/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 30 09:14:00 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 30 Jan 2014 08:14:00 -0000 Subject: [Pytest-commit] commit/py: hpk42: bump version to final 1.4.20 Message-ID: <20140130081400.1953.29100@app12.ash-private.bitbucket.org> 1 new commit in py: https://bitbucket.org/hpk42/py/commits/a3e0626aa0c5/ Changeset: a3e0626aa0c5 User: hpk42 Date: 2014-01-29 13:17:03 Summary: bump version to final 1.4.20 Affected #: 2 files diff -r 47280655743431abd4355062ae1db788790c582e -r a3e0626aa0c5aecf271367dc77e476ab216ea3c8 py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2013 """ -__version__ = '1.4.20.dev2' +__version__ = '1.4.20' from py import _apipkg diff -r 47280655743431abd4355062ae1db788790c582e -r a3e0626aa0c5aecf271367dc77e476ab216ea3c8 setup.py --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ name='py', description='library with cross-python path, ini-parsing, io, code, log facilities', long_description = open('README.txt').read(), - version='1.4.20.dev2', + version='1.4.20', url='http://pylib.readthedocs.org/', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 30 09:39:49 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 30 Jan 2014 08:39:49 -0000 Subject: [Pytest-commit] commit/py: hpk42: Added tag 1.4.20 for changeset a3e0626aa0c5 Message-ID: <20140130083949.5440.53422@app11.ash-private.bitbucket.org> 1 new commit in py: https://bitbucket.org/hpk42/py/commits/3c342e02f2a6/ Changeset: 3c342e02f2a6 User: hpk42 Date: 2014-01-30 09:39:39 Summary: Added tag 1.4.20 for changeset a3e0626aa0c5 Affected #: 1 file diff -r a3e0626aa0c5aecf271367dc77e476ab216ea3c8 -r 3c342e02f2a69b6c65dd9952a4a18a8e03aad80f .hgtags --- a/.hgtags +++ b/.hgtags @@ -53,3 +53,4 @@ c603503945f52b78522d96a423605cbc953236d3 1.4.17 c59201105a29801cc858eb9160b7a19791b91a35 1.4.18 284cc172e294d48edc840012e1451c32c3963d92 1.4.19 +a3e0626aa0c5aecf271367dc77e476ab216ea3c8 1.4.20 Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Jan 30 09:47:52 2014 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 30 Jan 2014 08:47:52 -0000 Subject: [Pytest-commit] commit/py: hpk42: include AUTHORS in manifest Message-ID: <20140130084752.23970.78040@app10.ash-private.bitbucket.org> 1 new commit in py: https://bitbucket.org/hpk42/py/commits/978558572564/ Changeset: 978558572564 User: hpk42 Date: 2014-01-30 09:47:46 Summary: include AUTHORS in manifest Affected #: 1 file diff -r 3c342e02f2a69b6c65dd9952a4a18a8e03aad80f -r 978558572564d033591cc73c3426ee1b68fa62ca MANIFEST.in --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ include CHANGELOG +include AUTHORS include README.txt include setup.py include LICENSE Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Thu Jan 30 13:07:13 2014 From: issues-reply at bitbucket.org (Wayne Werner) Date: Thu, 30 Jan 2014 12:07:13 -0000 Subject: [Pytest-commit] Issue #435: python_files causes reload to fail? (hpk42/pytest) Message-ID: <20140130120713.27550.46287@app13.ash-private.bitbucket.org> New issue 435: python_files causes reload to fail? https://bitbucket.org/hpk42/pytest/issue/435/python_files-causes-reload-to-fail Wayne Werner: I am the author of https://github.com/waynew/draftin-a-flask and am using py.test for all my testing needs (Frikken fantastic tool, thanks everyone for your work!) But I've come across the strangest issue. When I add [pytest] python_files=*.py to my tox.ini script, it seems to break the reload function. Check out revision aaf37795dfc49bd83e66976e3e781eb7a588caeb to observe this one weird behavior that developers love to hate. From issues-reply at bitbucket.org Fri Jan 31 01:12:20 2014 From: issues-reply at bitbucket.org (Marc Abramowitz) Date: Fri, 31 Jan 2014 00:12:20 -0000 Subject: [Pytest-commit] Issue #436: Presence of --junitxml junit.xml option and existence of junit.xml file causes conftest.py not to be loaded (hpk42/pytest) Message-ID: <20140131001220.14546.11363@app03.ash-private.bitbucket.org> New issue 436: Presence of --junitxml junit.xml option and existence of junit.xml file causes conftest.py not to be loaded https://bitbucket.org/hpk42/pytest/issue/436/presence-of-junitxml-junitxml-option-and Marc Abramowitz: Maybe or maybe not related to https://bitbucket.org/hpk42/pytest/issue/416/option-added-in-conftestpy-not-available, which uses a very similar example ("runslow) in fact. ``` $ pip freeze | grep pytest pytest==2.5.2 $ tree . ??? tests ??? conftest.py ??? test_stuff.py 1 directory, 2 files $ cat tests/conftest.py import pytest def pytest_addoption(parser): parser.addoption("--runslow", action="store_true", help="run slow tests") print("*** Added --runslow option") def pytest_runtest_setup(item): print("*** value of --runslow option: %r" % item.config.getoption("--runslow")) $ cat tests/test_stuff.py def test_stuff(): assert 1 + 1 == 2 ``` Now... The first time that I run `py.test` with `--junitxml junit.xml` and `-k test_stuff` and there is no `junit.xml` file yet, it works fine: ``` $ py.test --junitxml junit.xml --runslow -s -k test_stuff *** Added --runslow option ============================================================================= test session starts ============================================================================== platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2 collected 1 items tests/test_stuff.py *** value of --runslow option: True . ------------------------------------------------------------ generated xml file: /Users/marca/pytest-bug/junit.xml ------------------------------------------------------------- =========================================================================== 1 passed in 0.01 seconds =========================================================================== ``` Now that `junit.xml` exists: ``` $ ls -l junit.xml -rw-r--r-- 1 marca staff 215B Jan 30 16:06 junit.xml ``` A second invocation fails: ``` $ py.test --junitxml junit.xml --runslow -s -k test_stuff usage: py.test [options] [file_or_dir] [file_or_dir] [...] py.test: error: unrecognized arguments: --runslow ``` If I remove `--junitxml junit.xml`, it doesn't exhibit the problem: ``` $ py.test --runslow -s -k test_stuff *** Added --runslow option ============================================================================= test session starts ============================================================================== platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2 collected 1 items tests/test_stuff.py *** value of --runslow option: True . =========================================================================== 1 passed in 0.01 seconds =========================================================================== ``` It also goes away if I specify the `tests/` directory: ``` $ py.test --junitxml junit.xml --runslow -s -k test_stuff tests/ *** Added --runslow option ============================================================================= test session starts ============================================================================== platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2 collected 1 items tests/test_stuff.py *** value of --runslow option: True . ------------------------------------------------------------ generated xml file: /Users/marca/pytest-bug/junit.xml ------------------------------------------------------------- =========================================================================== 1 passed in 0.01 seconds =========================================================================== ``` I can't figure out what is going on here... From issues-reply at bitbucket.org Fri Jan 31 14:47:50 2014 From: issues-reply at bitbucket.org (Florian Rathgeber) Date: Fri, 31 Jan 2014 13:47:50 -0000 Subject: [Pytest-commit] Issue #437: Different tests collected on two nodes with xdist (hpk42/pytest) Message-ID: <20140131134750.17249.15413@app07.ash-private.bitbucket.org> New issue 437: Different tests collected on two nodes with xdist https://bitbucket.org/hpk42/pytest/issue/437/different-tests-collected-on-two-nodes Florian Rathgeber: When running py.test with xdist and -n 2 on Travis we occasionally get a ``` AssertionError: Different tests were collected between gw1 and gw0 ``` Here's an [example failure](https://travis-ci.org/firedrakeproject/firedrake/builds/17975334). We're not overriding the test collection hooks and I can't immediately think of any other way we might affect test collection. Tested with pytest 2.5.2, xdist 1.10, execnet 1.2.0. From issues-reply at bitbucket.org Fri Jan 31 15:42:30 2014 From: issues-reply at bitbucket.org (Edward Hope-Morley) Date: Fri, 31 Jan 2014 14:42:30 -0000 Subject: [Pytest-commit] Issue #150: posargs configerror (hpk42/tox) Message-ID: <20140131144230.25171.76365@app04.ash-private.bitbucket.org> New issue 150: posargs configerror https://bitbucket.org/hpk42/tox/issue/150/posargs-configerror Edward Hope-Morley: With tox version 1.7.0 I get the following error: tox.ConfigError: ConfigError: substitution key 'posargs' not found Which appears to be caused by the following line in my tox.ini: commands = python setup.py test --slowest --testr-args='{posargs}' This worked fine with the previous version of tox i.e. 1.6.1