From commits-noreply at bitbucket.org Wed Jul 3 11:47:30 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 03 Jul 2013 09:47:30 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: - add my ep2013 talk to talks
page
Message-ID: <20130703094730.13674.60247@bitbucket02.managed.contegix.com>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/a53052043acc/
Changeset: a53052043acc
User: hpk42
Date: 2013-07-03 11:47:18
Summary: - add my ep2013 talk to talks page
- add "talks/blogs" to the navigation side bar
Affected #: 3 files
diff -r 4cddadcc82d062982cd37f42f669a332f8ba372f -r a53052043acc302e0e9ded54e30d40809c87fda6 doc/en/_templates/localtoc.html
--- a/doc/en/_templates/localtoc.html
+++ b/doc/en/_templates/localtoc.html
@@ -31,6 +31,8 @@
issues[bb]
contact
+ |
+ Talks/Posts |
{% extends "basic/localtoc.html" %}
diff -r 4cddadcc82d062982cd37f42f669a332f8ba372f -r a53052043acc302e0e9ded54e30d40809c87fda6 doc/en/index.txt
--- a/doc/en/index.txt
+++ b/doc/en/index.txt
@@ -4,9 +4,6 @@
pytest: helps you write better programs
=============================================
-.. note:: Upcoming: `professional testing with pytest and tox `_ , 24th-26th June 2013, Leipzig.
-
-
**a mature full-featured Python testing tool**
- runs on Posix/Windows, Python 2.4-3.3, PyPy and Jython-2.5.1
diff -r 4cddadcc82d062982cd37f42f669a332f8ba372f -r a53052043acc302e0e9ded54e30d40809c87fda6 doc/en/talks.txt
--- a/doc/en/talks.txt
+++ b/doc/en/talks.txt
@@ -4,8 +4,6 @@
.. _`funcargs`: funcargs.html
-.. note:: Upcoming: `professional testing with pytest and tox <`http://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_ , 24th-26th June 2013, Leipzig.
-
Tutorial examples and blog postings
---------------------------------------------
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 Jul 4 17:20:38 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Thu, 04 Jul 2013 15:20:38 -0000
Subject: [Pytest-commit] commit/pytest: 4 new changesets
Message-ID: <20130704152038.27188.52802@bitbucket05.managed.contegix.com>
4 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/3445cabf1754/
Changeset: 3445cabf1754
User: ctheune
Date: 2013-07-03 19:41:05
Summary: Support working in a local virtualenv.
Affected #: 1 file
diff -r a53052043acc302e0e9ded54e30d40809c87fda6 -r 3445cabf175434fbe8b7a7f452c4418a4fb73095 .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -4,6 +4,13 @@
.svn
.hgsvn
+# Ingore local virtualenvs
+syntax:glob
+lib/
+bin/
+include/
+.Python/
+
# These lines are suggested according to the svn:ignore property
# Feel free to enable them by uncommenting them
syntax:glob
https://bitbucket.org/hpk42/pytest/commits/cf1c068a86dc/
Changeset: cf1c068a86dc
User: ctheune
Date: 2013-07-03 19:43:18
Summary: Compatibility with my spinal cord reflexes: colorize last summary line.
Provide a red bar if there are any 'failures'. Otherwise make it green.
Affected #: 1 file
diff -r 3445cabf175434fbe8b7a7f452c4418a4fb73095 -r cf1c068a86dcf5b61eeafaecc2c04392ac650fa1 _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -454,10 +454,14 @@
if val:
parts.append("%d %s" %(len(val), key))
line = ", ".join(parts)
- # XXX coloring
msg = "%s in %.2f seconds" %(line, session_duration)
if self.verbosity >= 0:
- self.write_sep("=", msg, bold=True)
+ markup = dict(bold=True)
+ if 'failed' in self.stats:
+ markup['red'] = True
+ else:
+ markup['green'] = True
+ self.write_sep("=", msg, **markup)
#else:
# self.write_line(msg, bold=True)
https://bitbucket.org/hpk42/pytest/commits/21c0abdd6cd4/
Changeset: 21c0abdd6cd4
Branch: ctheune/typo-1372873724648
User: ctheune
Date: 2013-07-03 19:48:57
Summary: Typo
Affected #: 1 file
diff -r cf1c068a86dcf5b61eeafaecc2c04392ac650fa1 -r 21c0abdd6cd4921cbe73aaa3008eb7a0c5ee7102 .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -1,10 +1,9 @@
-
# Automatically generated by `hgimportsvn`
syntax:glob
.svn
.hgsvn
-# Ingore local virtualenvs
+# Ignore local virtualenvs
syntax:glob
lib/
bin/
https://bitbucket.org/hpk42/pytest/commits/29461bb5660a/
Changeset: 29461bb5660a
User: ctheune
Date: 2013-07-03 19:49:28
Summary: Merged in ctheune/pytest-greenbar-1/ctheune/typo-1372873724648 (pull request #1)
Typo
Affected #: 1 file
diff -r cf1c068a86dcf5b61eeafaecc2c04392ac650fa1 -r 29461bb5660a9c38aed9a8762401afa8f9188149 .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -1,10 +1,9 @@
-
# Automatically generated by `hgimportsvn`
syntax:glob
.svn
.hgsvn
-# Ingore local virtualenvs
+# Ignore local virtualenvs
syntax:glob
lib/
bin/
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 Jul 6 15:51:15 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Sat, 06 Jul 2013 13:51:15 -0000
Subject: [Pytest-commit] commit/pytest: 2 new changesets
Message-ID: <20130706135115.4335.81121@bitbucket20.managed.contegix.com>
2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/8e8ca29faf60/
Changeset: 8e8ca29faf60
Branch: travis-integration
User: bubenkoff
Date: 2013-07-06 14:23:02
Summary: add travis integration, fixes for py25 and py27 no pyc tox env
Affected #: 4 files
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r 8e8ca29faf60b46b46c4c1ffd0808f77a80218d2 .gitignore
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+# Automatically generated by `hgimportsvn`
+.svn
+.hgsvn
+
+# Ignore local virtualenvs
+lib/
+bin/
+include/
+.Python/
+
+# These lines are suggested according to the svn:ignore property
+# Feel free to enable them by uncommenting them
+*.pyc
+*.pyo
+*.swp
+*.html
+*.class
+*.orig
+*~
+
+doc/*/_build
+build/
+dist/
+*.egg-info
+issue/
+env/
+3rdparty/
+.tox
+.cache
+.coverage
+.ropeproject
+
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r 8e8ca29faf60b46b46c4c1ffd0808f77a80218d2 .travis.yml
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,10 @@
+language: python
+# command to install dependencies
+install: "pip install -e . detox"
+# # command to run tests
+script: detox --recreate
+notifications:
+ irc:
+ - "chat.freenode.net#pylib"
+ email:
+ - pytest-commit at python.org
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r 8e8ca29faf60b46b46c4c1ffd0808f77a80218d2 README.rst
--- a/README.rst
+++ b/README.rst
@@ -16,6 +16,9 @@
- many `external plugins `_.
+.. image:: https://secure.travis-ci.org/bubenkoff/pytest.png?branch=travis-integration
+ :target: http://travis-ci.org/bubenkoff/pytest
+
A simple example for a test::
# content of test_module.py
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r 8e8ca29faf60b46b46c4c1ffd0808f77a80218d2 tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -13,6 +13,10 @@
changedir=.
commands= py.test --genscript=pytest1
+[testenv:py25]
+setenv =
+ PIP_INSECURE=1
+
[testenv:py27-xdist]
changedir=.
basepython=python2.7
@@ -29,6 +33,7 @@
deps=pytest-xdist
setenv=
PYTHONDONTWRITEBYTECODE=1
+distribute=true
commands=
py.test -n3 -rfsxX \
--junitxml={envlogdir}/junit-{envname}.xml {posargs:testing}
https://bitbucket.org/hpk42/pytest/commits/c3a0a8895e55/
Changeset: c3a0a8895e55
User: hpk42
Date: 2013-07-06 15:51:14
Summary: Merged in bubenkoff/pytest/travis-integration (pull request #41)
add travis integration, fixes for py25 and py27 no pyc tox env
Affected #: 4 files
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r c3a0a8895e55c89070142e3849959464d08514b6 .gitignore
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+# Automatically generated by `hgimportsvn`
+.svn
+.hgsvn
+
+# Ignore local virtualenvs
+lib/
+bin/
+include/
+.Python/
+
+# These lines are suggested according to the svn:ignore property
+# Feel free to enable them by uncommenting them
+*.pyc
+*.pyo
+*.swp
+*.html
+*.class
+*.orig
+*~
+
+doc/*/_build
+build/
+dist/
+*.egg-info
+issue/
+env/
+3rdparty/
+.tox
+.cache
+.coverage
+.ropeproject
+
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r c3a0a8895e55c89070142e3849959464d08514b6 .travis.yml
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,10 @@
+language: python
+# command to install dependencies
+install: "pip install -e . detox"
+# # command to run tests
+script: detox --recreate
+notifications:
+ irc:
+ - "chat.freenode.net#pylib"
+ email:
+ - pytest-commit at python.org
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r c3a0a8895e55c89070142e3849959464d08514b6 README.rst
--- a/README.rst
+++ b/README.rst
@@ -16,6 +16,9 @@
- many `external plugins `_.
+.. image:: https://secure.travis-ci.org/bubenkoff/pytest.png?branch=travis-integration
+ :target: http://travis-ci.org/bubenkoff/pytest
+
A simple example for a test::
# content of test_module.py
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r c3a0a8895e55c89070142e3849959464d08514b6 tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -13,6 +13,10 @@
changedir=.
commands= py.test --genscript=pytest1
+[testenv:py25]
+setenv =
+ PIP_INSECURE=1
+
[testenv:py27-xdist]
changedir=.
basepython=python2.7
@@ -29,6 +33,7 @@
deps=pytest-xdist
setenv=
PYTHONDONTWRITEBYTECODE=1
+distribute=true
commands=
py.test -n3 -rfsxX \
--junitxml={envlogdir}/junit-{envname}.xml {posargs:testing}
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 Jul 6 11:04:30 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Sat, 06 Jul 2013 09:04:30 -0000
Subject: [Pytest-commit] commit/pytest: 4 new changesets
Message-ID: <20130706090430.12145.36142@bitbucket01.managed.contegix.com>
4 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/25983ac76a78/
Changeset: 25983ac76a78
User: flub
Date: 2013-04-18 13:24:53
Summary: Load conftest files in the correct order initially
When the conftest.py files are looked for intially they got loaded
starting from the subdir ending at the parent dir(s). Later on during
collection any conftest.py files are loaded starting from the parent
dir ending at the subdir. Due to how extending fixtures works the
latter is correct as otherwise the wrong fixture will be available.
So this changes the initial conftest loading to start at the root and
go towards the subdir.
This does also affect the order of other hooks, hence the order of the
reporting being different in testing/test_terminal.py.
Affected #: 4 files
diff -r fdc28ac2029f1c0be1dac4991c2f1b014c39a03f -r 25983ac76a7887522684bca6a9173d23e5adc30c _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -196,27 +196,20 @@
self.getconftestmodules(x)
def getconftestmodules(self, path):
- """ return a list of imported conftest modules for the given path. """
try:
clist = self._path2confmods[path]
except KeyError:
if path is None:
- raise ValueError("missing default confest.")
- dp = path.dirpath()
+ raise ValueError("missing default conftest.")
clist = []
- if dp != path:
- cutdir = self._confcutdir
- if cutdir and path != cutdir and not path.relto(cutdir):
- pass
- else:
- conftestpath = path.join("conftest.py")
- if conftestpath.check(file=1):
- clist.append(self.importconftest(conftestpath))
- clist[:0] = self.getconftestmodules(dp)
+ for parent in path.parts():
+ if self._confcutdir and self._confcutdir.relto(parent):
+ continue
+ conftestpath = parent.join("conftest.py")
+ if conftestpath.check(file=1):
+ clist.append(self.importconftest(conftestpath))
self._path2confmods[path] = clist
- # be defensive: avoid changes from caller side to
- # affect us by always returning a copy of the actual list
- return clist[:]
+ return clist
def rget(self, name, path=None):
mod, value = self.rget_with_confmod(name, path)
diff -r fdc28ac2029f1c0be1dac4991c2f1b014c39a03f -r 25983ac76a7887522684bca6a9173d23e5adc30c testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -102,6 +102,77 @@
"*2 passed*"
])
+ def test_extend_fixture_module_class(self, testdir):
+ testfile = testdir.makepyfile("""
+ import pytest
+
+ @pytest.fixture
+ def spam():
+ return 'spam'
+
+ class TestSpam:
+
+ @pytest.fixture
+ def spam(self, spam):
+ return spam * 2
+
+ def test_spam(self, spam):
+ assert spam == 'spamspam'
+ """)
+ result = testdir.runpytest()
+ result.stdout.fnmatch_lines(["*1 passed*"])
+ result = testdir.runpytest(testfile)
+ result.stdout.fnmatch_lines(["*1 passed*"])
+
+ def test_extend_fixture_conftest_module(self, testdir):
+ testdir.makeconftest("""
+ import pytest
+
+ @pytest.fixture
+ def spam():
+ return 'spam'
+ """)
+ testfile = testdir.makepyfile("""
+ import pytest
+
+ @pytest.fixture
+ def spam(spam):
+ return spam * 2
+
+ def test_spam(spam):
+ assert spam == 'spamspam'
+ """)
+ result = testdir.runpytest()
+ result.stdout.fnmatch_lines(["*1 passed*"])
+ result = testdir.runpytest(testfile)
+ result.stdout.fnmatch_lines(["*1 passed*"])
+
+ def test_extend_fixture_conftest_conftest(self, testdir):
+ testdir.makeconftest("""
+ import pytest
+
+ @pytest.fixture
+ def spam():
+ return 'spam'
+ """)
+ pkg = testdir.mkpydir("pkg")
+ pkg.join("conftest.py").write(py.code.Source("""
+ import pytest
+
+ @pytest.fixture
+ def spam(spam):
+ return spam * 2
+ """))
+ testfile = pkg.join("test_spam.py")
+ testfile.write(py.code.Source("""
+ def test_spam(spam):
+ assert spam == "spamspam"
+ """))
+ result = testdir.runpytest()
+ result.stdout.fnmatch_lines(["*1 passed*"])
+ result = testdir.runpytest(testfile)
+ result.stdout.fnmatch_lines(["*1 passed*"])
+
def test_funcarg_lookup_error(self, testdir):
p = testdir.makepyfile("""
def test_lookup_error(unknown):
diff -r fdc28ac2029f1c0be1dac4991c2f1b014c39a03f -r 25983ac76a7887522684bca6a9173d23e5adc30c testing/test_conftest.py
--- a/testing/test_conftest.py
+++ b/testing/test_conftest.py
@@ -204,3 +204,15 @@
"""))
result = testdir.runpytest("-h", "--confcutdir=%s" % x, x)
result.stdout.fnmatch_lines(["*--xyz*"])
+
+def test_conftest_import_order(testdir, monkeypatch):
+ ct1 = testdir.makeconftest("")
+ sub = testdir.mkdir("sub")
+ ct2 = sub.join("conftest.py")
+ ct2.write("")
+ def impct(p):
+ print p
+ return p
+ conftest = Conftest()
+ monkeypatch.setattr(conftest, 'importconftest', impct)
+ assert conftest.getconftestmodules(sub) == [ct1, ct2]
diff -r fdc28ac2029f1c0be1dac4991c2f1b014c39a03f -r 25983ac76a7887522684bca6a9173d23e5adc30c testing/test_terminal.py
--- a/testing/test_terminal.py
+++ b/testing/test_terminal.py
@@ -643,9 +643,9 @@
""")
result = testdir.runpytest("a")
result.stdout.fnmatch_lines([
+ "*hello: 42*",
"line1",
str(testdir.tmpdir),
- "*hello: 42*",
])
@pytest.mark.xfail("not hasattr(os, 'dup')")
https://bitbucket.org/hpk42/pytest/commits/32065167d928/
Changeset: 32065167d928
User: bubenkoff
Date: 2013-07-06 10:06:12
Summary: merge with upstream
Affected #: 60 files
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -1,9 +1,15 @@
-
# Automatically generated by `hgimportsvn`
syntax:glob
.svn
.hgsvn
+# Ignore local virtualenvs
+syntax:glob
+lib/
+bin/
+include/
+.Python/
+
# These lines are suggested according to the svn:ignore property
# Feel free to enable them by uncommenting them
syntax:glob
@@ -25,3 +31,4 @@
.tox
.cache
.coverage
+.ropeproject
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -54,3 +54,9 @@
8738b828dec53937765db71951ef955cca4c51f6 2.3.2
7fe44182c434f8ac89149a3c340479872a5d5ccb 2.3.3
ef299e57f24218dbdd949498d7e660723636bcc3 2.3.4
+fc3a793e87ec907000a47ea0d3a372a2fe218c0a 2.3.5
+b93ac0cdae02effaa3c136a681cc45bba757fe46 1.4.14
+b93ac0cdae02effaa3c136a681cc45bba757fe46 1.4.14
+0000000000000000000000000000000000000000 1.4.14
+0000000000000000000000000000000000000000 1.4.14
+0000000000000000000000000000000000000000 1.4.14
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 AUTHORS
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,9 +6,14 @@
Ronny Pfannschmidt
Benjamin Peterson
Floris Bruynooghe
+Jason R. Coombs
+Wouter van Ackooy
Samuele Pedroni
+Brianna Laugher
Carl Friedrich Bolz
Armin Rigo
+Maho
+Jaap Broekhuizen
Maciek Fijalkowski
Guido Wesdorp
Brian Dorsey
@@ -25,3 +30,4 @@
Daniel Nuri
Graham Horler
Andreas Zeidler
+Brian Okken
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,61 @@
-Changes between 2.3.4 and 2.3.5dev
+Changes between 2.3.5 and 2.4.DEV
-----------------------------------
+- 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
+ 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 --
+ files without any doctest items will not show up anymore
+ and doctest examples are counted as separate test items.
+ thanks Danilo Bellini.
+
+- fix issue245 by depending on the released py-1.4.14
+ which fixes py.io.dupfile to work with files with no
+ mode. Thanks Jason R. Coombs.
+
+- fix junitxml generation when test output contains control characters,
+ addressing issue267, thanks Jaap Broekhuizen
+
+- honor --tb style for setup/teardown errors as well. Thanks Maho.
+
+- fix issue307 - use yaml.safe_load in example, thanks Mark Eichin.
+
+
+Changes between 2.3.4 and 2.3.5
+-----------------------------------
+
+- never consider a fixture function for test function collection
+
+- allow re-running of test items / helps to fix pytest-reruntests plugin
+ and also help to keep less fixture/resource references alive
+
- put captured stdout/stderr into junitxml output even for passing tests
(thanks Adam Goucher)
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/__init__.py
--- a/_pytest/__init__.py
+++ b/_pytest/__init__.py
@@ -1,2 +1,2 @@
#
-__version__ = '2.3.5.dev8'
+__version__ = '2.4.0.dev5'
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/assertion/rewrite.py
--- a/_pytest/assertion/rewrite.py
+++ b/_pytest/assertion/rewrite.py
@@ -177,6 +177,10 @@
# This happens when we get a EEXIST in find_module creating the
# __pycache__ directory and __pycache__ is by some non-dir node.
return False
+ elif err == errno.EACCES:
+ # The directory is read-only; this can happen for example when
+ # running the tests in a package installed as root
+ return False
raise
try:
fp.write(imp.get_magic())
@@ -215,11 +219,17 @@
if (not source.startswith(BOM_UTF8) and
(not cookie_re.match(source[0:end1]) or
not cookie_re.match(source[end1:end2]))):
+ if hasattr(state, "_indecode"):
+ return None # encodings imported us again, we don't rewrite
+ state._indecode = True
try:
- source.decode("ascii")
- except UnicodeDecodeError:
- # Let it fail in real import.
- return None
+ try:
+ source.decode("ascii")
+ except UnicodeDecodeError:
+ # Let it fail in real import.
+ return None
+ finally:
+ del state._indecode
# On Python versions which are not 2.7 and less than or equal to 3.1, the
# parser expects *nix newlines.
if REWRITE_NEWLINES:
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/assertion/util.py
--- a/_pytest/assertion/util.py
+++ b/_pytest/assertion/util.py
@@ -10,6 +10,7 @@
# DebugInterpreter.
_reprcompare = None
+
def format_explanation(explanation):
"""This formats an explanation
@@ -85,7 +86,7 @@
def assertrepr_compare(config, op, left, right):
"""Return specialised explanations for some operators/operands"""
- width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op
+ 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)
@@ -93,7 +94,7 @@
issequence = lambda x: isinstance(x, (list, tuple))
istext = lambda x: isinstance(x, basestring)
isdict = lambda x: isinstance(x, dict)
- isset = lambda x: isinstance(x, set)
+ isset = lambda x: isinstance(x, (set, frozenset))
verbose = config.getoption('verbose')
explanation = None
@@ -114,9 +115,9 @@
raise
except:
excinfo = py.code.ExceptionInfo()
- explanation = ['(pytest_assertion plugin: representation of '
- 'details failed. Probably an object has a faulty __repr__.)',
- str(excinfo)]
+ explanation = [
+ '(pytest_assertion plugin: representation of details failed. '
+ 'Probably an object has a faulty __repr__.)', str(excinfo)]
if not explanation:
return None
@@ -132,7 +133,7 @@
"""
explanation = []
if not verbose:
- i = 0 # just in case left or right has zero length
+ i = 0 # just in case left or right has zero length
for i in range(min(len(left), len(right))):
if left[i] != right[i]:
break
@@ -166,13 +167,15 @@
(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 += [
+ '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' % py.io.saferepr(right[len(left)],)]
- return explanation # + _diff_text(py.std.pprint.pformat(left),
- # py.std.pprint.pformat(right))
+ explanation += [
+ '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))
def _compare_eq_set(left, right, verbose=False):
@@ -210,12 +213,12 @@
if extra_left:
explanation.append('Left contains more items:')
explanation.extend(py.std.pprint.pformat(
- dict((k, left[k]) for k in extra_left)).splitlines())
+ 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.extend(py.std.pprint.pformat(
- dict((k, right[k]) for k in extra_right)).splitlines())
+ dict((k, right[k]) for k in extra_right)).splitlines())
return explanation
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/doctest.py
--- a/_pytest/doctest.py
+++ b/_pytest/doctest.py
@@ -34,6 +34,14 @@
self.reprlocation.toterminal(tw)
class DoctestItem(pytest.Item):
+ def __init__(self, name, parent, runner=None, dtest=None):
+ super(DoctestItem, self).__init__(name, parent)
+ self.runner = runner
+ self.dtest = dtest
+
+ def runtest(self):
+ self.runner.run(self.dtest)
+
def repr_failure(self, excinfo):
doctest = py.std.doctest
if excinfo.errisinstance((doctest.DocTestFailure,
@@ -76,7 +84,7 @@
return super(DoctestItem, self).repr_failure(excinfo)
def reportinfo(self):
- return self.fspath, None, "[doctest]"
+ return self.fspath, None, "[doctest] %s" % self.name
class DoctestTextfile(DoctestItem, pytest.File):
def runtest(self):
@@ -91,8 +99,8 @@
extraglobs=dict(getfixture=fixture_request.getfuncargvalue),
raise_on_error=True, verbose=0)
-class DoctestModule(DoctestItem, pytest.File):
- def runtest(self):
+class DoctestModule(pytest.File):
+ def collect(self):
doctest = py.std.doctest
if self.fspath.basename == "conftest.py":
module = self.config._conftest.importconftest(self.fspath)
@@ -102,7 +110,11 @@
self.funcargs = {}
self._fixtureinfo = FuncFixtureInfo((), [], {})
fixture_request = FixtureRequest(self)
- failed, tot = doctest.testmod(
- module, raise_on_error=True, verbose=0,
- extraglobs=dict(getfixture=fixture_request.getfuncargvalue),
- optionflags=doctest.ELLIPSIS)
+ doctest_globals = dict(getfixture=fixture_request.getfuncargvalue)
+ # uses internal doctest module parsing mechanism
+ finder = doctest.DocTestFinder()
+ runner = doctest.DebugRunner(verbose=0, optionflags=doctest.ELLIPSIS)
+ for test in finder.find(module, module.__name__,
+ extraglobs=doctest_globals):
+ if test.examples: # skip empty doctests
+ yield DoctestItem(test.name, self, runner, test)
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/junitxml.py
--- a/_pytest/junitxml.py
+++ b/_pytest/junitxml.py
@@ -36,7 +36,8 @@
# | [#x10000-#x10FFFF]
_legal_chars = (0x09, 0x0A, 0x0d)
_legal_ranges = (
- (0x20, 0xD7FF),
+ (0x20, 0x7E),
+ (0x80, 0xD7FF),
(0xE000, 0xFFFD),
(0x10000, 0x10FFFF),
)
@@ -103,7 +104,7 @@
classnames.insert(0, self.prefix)
self.tests.append(Junit.testcase(
classname=".".join(classnames),
- name=names[-1],
+ name=bin_xml_escape(names[-1]),
time=getattr(report, 'duration', 0)
))
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/main.py
--- a/_pytest/main.py
+++ b/_pytest/main.py
@@ -97,6 +97,7 @@
if session._testsfailed:
session.exitstatus = EXIT_TESTSFAILED
finally:
+ session.startdir.chdir()
if initstate >= 2:
config.hook.pytest_sessionfinish(
session=session,
@@ -216,6 +217,9 @@
#: keywords/markers collected from all scopes
self.keywords = NodeKeywords(self)
+ #: allow adding of extra keywords to use for matching
+ self.extra_keyword_matches = set()
+
#self.extrainit()
@property
@@ -307,6 +311,14 @@
chain.reverse()
return chain
+ def listextrakeywords(self):
+ """ Return a set of all extra keywords in self and any parents."""
+ extra_keywords = set()
+ item = self
+ for item in self.listchain():
+ extra_keywords.update(item.extra_keyword_matches)
+ return extra_keywords
+
def listnames(self):
return [x.name for x in self.listchain()]
@@ -441,6 +453,7 @@
self.shouldstop = False
self.trace = config.trace.root.get("collection")
self._norecursepatterns = config.getini("norecursedirs")
+ self.startdir = py.path.local()
def pytest_collectstart(self):
if self.shouldstop:
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/mark.py
--- a/_pytest/mark.py
+++ b/_pytest/mark.py
@@ -1,44 +1,56 @@
""" generic mechanism for marking and selecting python functions. """
import pytest, py
+
def pytest_namespace():
return {'mark': MarkGenerator()}
+
def pytest_addoption(parser):
group = parser.getgroup("general")
- group._addoption('-k',
+ group._addoption(
+ '-k',
action="store", dest="keyword", default='', metavar="EXPRESSION",
help="only run tests which match the given substring expression. "
"An expression is a python evaluatable expression "
"where all names are substring-matched against test names "
- "and keywords. Example: -k 'test_method or test_other' "
- "matches all test functions whose name contains "
- "'test_method' or 'test_other'.")
+ "and their parent classes. Example: -k 'test_method or test "
+ "other' matches all test functions and classes whose name "
+ "contains 'test_method' or 'test_other'. "
+ "Additionally keywords are matched to classes and functions "
+ "containing extra names in their 'extra_keyword_matches' set, "
+ "as well as functions which have names assigned directly to them."
+ )
- group._addoption("-m",
+ group._addoption(
+ "-m",
action="store", dest="markexpr", default="", metavar="MARKEXPR",
help="only run tests matching given mark expression. "
"example: -m 'mark1 and not mark2'."
- )
+ )
- group.addoption("--markers", action="store_true", help=
- "show markers (builtin, plugin and per-project ones).")
+ group.addoption(
+ "--markers", action="store_true",
+ help="show markers (builtin, plugin and per-project ones)."
+ )
parser.addini("markers", "markers for test functions", 'linelist')
+
def pytest_cmdline_main(config):
if config.option.markers:
config.pluginmanager.do_configure(config)
tw = py.io.TerminalWriter()
for line in config.getini("markers"):
name, rest = line.split(":", 1)
- tw.write("@pytest.mark.%s:" % name, bold=True)
+ tw.write("@pytest.mark.%s:" % name, bold=True)
tw.line(rest)
tw.line()
config.pluginmanager.do_unconfigure(config)
return 0
pytest_cmdline_main.tryfirst = True
+
def pytest_collection_modifyitems(items, config):
keywordexpr = config.option.keyword
matchexpr = config.option.markexpr
@@ -67,32 +79,76 @@
config.hook.pytest_deselected(items=deselected)
items[:] = remaining
-class BoolDict:
- def __init__(self, mydict):
- self._mydict = mydict
- def __getitem__(self, name):
- return name in self._mydict
-class SubstringDict:
- def __init__(self, mydict):
- self._mydict = mydict
- def __getitem__(self, name):
- for key in self._mydict:
- if name in key:
+class MarkMapping:
+ """Provides a local mapping for markers.
+ Only the marker names from the given :class:`NodeKeywords` will be mapped,
+ so the names are taken only from :class:`MarkInfo` or
+ :class:`MarkDecorator` items.
+ """
+ def __init__(self, keywords):
+ mymarks = set()
+ for key, value in keywords.items():
+ if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator):
+ mymarks.add(key)
+ self._mymarks = mymarks
+
+ def __getitem__(self, markname):
+ return markname in self._mymarks
+
+
+class KeywordMapping:
+ """Provides a local mapping for keywords.
+ Given a list of names, map any substring of one of these names to True.
+ """
+ def __init__(self, names):
+ self._names = names
+
+ def __getitem__(self, subname):
+ for name in self._names:
+ if subname in name:
return True
return False
-def matchmark(colitem, matchexpr):
- return eval(matchexpr, {}, BoolDict(colitem.keywords))
+
+def matchmark(colitem, markexpr):
+ """Tries to match on any marker names, attached to the given colitem."""
+ return eval(markexpr, {}, MarkMapping(colitem.keywords))
+
def matchkeyword(colitem, keywordexpr):
+ """Tries to match given keyword expression to given collector item.
+
+ Will match on the name of colitem, including the names of its parents.
+ Only matches names of items which are either a :class:`Class` or a
+ :class:`Function`.
+ Additionally, matches on names in the 'extra_keyword_matches' set of
+ any item, as well as names directly assigned to test functions.
+ """
keywordexpr = keywordexpr.replace("-", "not ")
- return eval(keywordexpr, {}, SubstringDict(colitem.keywords))
+ mapped_names = set()
+
+ # Add the names of the current item and any parent items
+ for item in colitem.listchain():
+ if not isinstance(item, pytest.Instance):
+ mapped_names.add(item.name)
+
+ # Add the names added as extra keywords to current or parent items
+ for name in colitem.listextrakeywords():
+ mapped_names.add(name)
+
+ # Add the names attached to the current function through direct assignment
+ for name in colitem.function.__dict__:
+ mapped_names.add(name)
+
+ return eval(keywordexpr, {}, KeywordMapping(mapped_names))
+
def pytest_configure(config):
if config.option.strict:
pytest.mark._config = config
+
class MarkGenerator:
""" Factory for :class:`MarkDecorator` objects - exposed as
a ``py.test.mark`` singleton instance. Example::
@@ -126,6 +182,7 @@
if name not in self._markers:
raise AttributeError("%r not a registered marker" % (name,))
+
class MarkDecorator:
""" A decorator for test functions and test classes. When applied
it will create :class:`MarkInfo` objects which may be
@@ -149,7 +206,7 @@
def __repr__(self):
d = self.__dict__.copy()
name = d.pop('markname')
- return "" %(name, d)
+ return "" % (name, d)
def __call__(self, *args, **kwargs):
""" if passed a single callable argument: decorate it with mark info.
@@ -162,15 +219,17 @@
if hasattr(func, 'pytestmark'):
l = func.pytestmark
if not isinstance(l, list):
- func.pytestmark = [l, self]
+ func.pytestmark = [l, self]
else:
- l.append(self)
+ l.append(self)
else:
- func.pytestmark = [self]
+ func.pytestmark = [self]
else:
holder = getattr(func, self.markname, None)
if holder is None:
- holder = MarkInfo(self.markname, self.args, self.kwargs)
+ holder = MarkInfo(
+ self.markname, self.args, self.kwargs
+ )
setattr(func, self.markname, holder)
else:
holder.add(self.args, self.kwargs)
@@ -180,6 +239,7 @@
args = self.args + args
return self.__class__(self.markname, args=args, kwargs=kw)
+
class MarkInfo:
""" Marking object created by :class:`MarkDecorator` instances. """
def __init__(self, name, args, kwargs):
@@ -193,7 +253,8 @@
def __repr__(self):
return "" % (
- self.name, self.args, self.kwargs)
+ self.name, self.args, self.kwargs
+ )
def add(self, args, kwargs):
""" add a MarkInfo with the given args and kwargs. """
@@ -205,4 +266,3 @@
""" yield MarkInfo objects each relating to a marking-call. """
for args, kwargs in self._arglist:
yield MarkInfo(self.name, args, kwargs)
-
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -4,6 +4,7 @@
import sys
import pytest
from _pytest.main import getfslineno
+from _pytest.mark import MarkDecorator, MarkInfo
from _pytest.monkeypatch import monkeypatch
from py._code.code import TerminalRepr
@@ -177,7 +178,8 @@
if collector.classnamefilter(name):
Class = collector._getcustomclass("Class")
return Class(name, parent=collector)
- elif collector.funcnamefilter(name) and hasattr(obj, '__call__'):
+ elif collector.funcnamefilter(name) and hasattr(obj, '__call__') and \
+ getfixturemarker(obj) is None:
if is_generator(obj):
return Generator(name, parent=collector)
else:
@@ -369,7 +371,9 @@
return mod
def setup(self):
- setup_module = xunitsetup(self.obj, "setup_module")
+ setup_module = xunitsetup(self.obj, "setUpModule")
+ if setup_module is None:
+ setup_module = xunitsetup(self.obj, "setup_module")
if setup_module is not None:
#XXX: nose compat hack, move to nose plugin
# if it takes a positional arg, its probably a pytest style one
@@ -380,7 +384,9 @@
setup_module()
def teardown(self):
- teardown_module = xunitsetup(self.obj, 'teardown_module')
+ teardown_module = xunitsetup(self.obj, 'tearDownModule')
+ if teardown_module is None:
+ teardown_module = xunitsetup(self.obj, 'teardown_module')
if teardown_module is not None:
#XXX: nose compat hack, move to nose plugin
# if it takes a positional arg, its probably a py.test style one
@@ -564,11 +570,13 @@
self._globalid_args = set()
self._globalparam = _notexists
self._arg2scopenum = {} # used for sorting parametrized resources
+ self.keywords = {}
def copy(self, metafunc):
cs = CallSpec2(self.metafunc)
cs.funcargs.update(self.funcargs)
cs.params.update(self.params)
+ cs.keywords.update(self.keywords)
cs._arg2scopenum.update(self._arg2scopenum)
cs._idlist = list(self._idlist)
cs._globalid = self._globalid
@@ -592,7 +600,7 @@
def id(self):
return "-".join(map(str, filter(None, self._idlist)))
- def setmulti(self, valtype, argnames, valset, id, scopenum=0):
+ def setmulti(self, valtype, argnames, valset, id, keywords, scopenum=0):
for arg,val in zip(argnames, valset):
self._checkargnotcontained(arg)
getattr(self, valtype)[arg] = val
@@ -604,6 +612,7 @@
if val is _notexists:
self._emptyparamspecified = True
self._idlist.append(id)
+ self.keywords.update(keywords)
def setall(self, funcargs, id, param):
for x in funcargs:
@@ -644,13 +653,15 @@
during the collection phase. If you need to setup expensive resources
see about setting indirect=True to do it rather at test setup time.
- :arg argnames: an argument name or a list of argument names
+ :arg argnames: a comma-separated string denoting one or more argument
+ names, or a list/tuple of argument strings.
- :arg argvalues: The list of argvalues determines how often a test is invoked
- with different argument values. If only one argname was specified argvalues
- is a list of simple values. If N argnames were specified, argvalues must
- be a list of N-tuples, where each tuple-element specifies a value for its
- respective argname.
+ :arg argvalues: The list of argvalues determines how often a
+ test is invoked with different argument values. If only one
+ argname was specified argvalues is a list of simple values. If N
+ argnames were specified, argvalues must be a list of N-tuples,
+ where each tuple-element specifies a value for its respective
+ argname.
:arg indirect: if True each argvalue corresponding to an argname will
be passed as request.param to its respective argname fixture
@@ -666,8 +677,24 @@
It will also override any fixture-function defined scope, allowing
to set a dynamic scope using test context or configuration.
"""
+
+ # individual parametrized argument sets can be wrapped in a
+ # marker in which case we unwrap the values and apply the mark
+ # at Function init
+ newkeywords = {}
+ unwrapped_argvalues = []
+ for i, argval in enumerate(argvalues):
+ if isinstance(argval, MarkDecorator):
+ newmark = MarkDecorator(argval.markname,
+ argval.args[:-1], argval.kwargs)
+ newkeywords[i] = {newmark.markname: newmark}
+ argval = argval.args[-1]
+ unwrapped_argvalues.append(argval)
+ argvalues = unwrapped_argvalues
+
if not isinstance(argnames, (tuple, list)):
- argnames = (argnames,)
+ argnames = [x.strip() for x in argnames.split(",") if x.strip()]
+ if len(argnames) == 1:
argvalues = [(val,) for val in argvalues]
if not argvalues:
argvalues = [(_notexists,) * len(argnames)]
@@ -690,7 +717,7 @@
assert len(valset) == len(argnames)
newcallspec = callspec.copy(self)
newcallspec.setmulti(valtype, argnames, valset, ids[i],
- scopenum)
+ newkeywords.get(i, {}), scopenum)
newcalls.append(newcallspec)
self._calls = newcalls
@@ -907,6 +934,9 @@
for name, val in (py.builtin._getfuncdict(self.obj) or {}).items():
self.keywords[name] = val
+ if callspec:
+ for name, val in callspec.keywords.items():
+ self.keywords[name] = val
if keywords:
for name, val in keywords.items():
self.keywords[name] = val
@@ -917,20 +947,25 @@
self.cls,
funcargs=not isyield)
self.fixturenames = fi.names_closure
- if isyield:
- assert not callspec, (
+ if callspec is not None:
+ self.callspec = callspec
+ self._initrequest()
+
+ def _initrequest(self):
+ if self._isyieldedfunction():
+ assert not hasattr(self, "callspec"), (
"yielded functions (deprecated) cannot have funcargs")
self.funcargs = {}
else:
- if callspec is not None:
- self.callspec = callspec
- self.funcargs = callspec.funcargs or {}
+ if hasattr(self, "callspec"):
+ callspec = self.callspec
+ self.funcargs = callspec.funcargs.copy()
self._genid = callspec.id
if hasattr(callspec, "param"):
self.param = callspec.param
else:
self.funcargs = {}
- self._request = req = FixtureRequest(self)
+ self._request = FixtureRequest(self)
@property
def function(self):
@@ -1561,15 +1596,7 @@
continue
# fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
# or are "@pytest.fixture" marked
- try:
- marker = obj._pytestfixturefunction
- except KeyboardInterrupt:
- raise
- except Exception:
- # some objects raise errors like request (from flask import request)
- # we don't expect them to be fixture functions
- marker = None
-
+ marker = getfixturemarker(obj)
if marker is None:
if not name.startswith(self._argprefix):
continue
@@ -1615,6 +1642,29 @@
except ValueError:
pass
+def call_fixture_func(fixturefunc, request, kwargs):
+ if is_generator(fixturefunc):
+ iter = fixturefunc(**kwargs)
+ next = getattr(iter, "__next__", None)
+ if next is None:
+ next = getattr(iter, "next")
+ res = next()
+ def teardown():
+ try:
+ next()
+ except StopIteration:
+ pass
+ else:
+ fs, lineno = getfslineno(fixturefunc)
+ location = "%s:%s" % (fs, lineno+1)
+ pytest.fail(
+ "fixture function %s has more than one 'yield': \n%s" %
+ (fixturefunc.__name__, location), pytrace=False)
+ request.addfinalizer(teardown)
+ else:
+ res = fixturefunc(**kwargs)
+ return res
+
class FixtureDef:
""" A container for a factory definition. """
def __init__(self, fixturemanager, baseid, argname, func, scope, params,
@@ -1665,7 +1715,7 @@
fixturefunc = fixturefunc.__get__(request.instance)
except AttributeError:
pass
- result = fixturefunc(**kwargs)
+ result = call_fixture_func(fixturefunc, request, kwargs)
assert not hasattr(self, "cached_result")
self.cached_result = result
return result
@@ -1697,29 +1747,39 @@
def parametrize_sorted(items, ignore, cache, scopenum):
if scopenum >= 3:
return items
- newitems = []
- olditems = []
+
+ # we pick the first item which has a arg/param combo in the
+ # requested scope and sort other items with the same combo
+ # into "newitems" which then is a list of all items using this
+ # arg/param.
+
+ similar_items = []
+ other_items = []
slicing_argparam = None
+ slicing_index = 0
for item in items:
argparamlist = getfuncargparams(item, ignore, scopenum, cache)
if slicing_argparam is None and argparamlist:
slicing_argparam = argparamlist[0]
- slicing_index = len(olditems)
+ slicing_index = len(other_items)
if slicing_argparam in argparamlist:
- newitems.append(item)
+ similar_items.append(item)
else:
- olditems.append(item)
- if newitems:
+ other_items.append(item)
+
+ if (len(similar_items) + slicing_index) > 1:
newignore = ignore.copy()
newignore.add(slicing_argparam)
- newitems = parametrize_sorted(newitems + olditems[slicing_index:],
- newignore, cache, scopenum)
- old1 = parametrize_sorted(olditems[:slicing_index], newignore,
- cache, scopenum+1)
- return old1 + newitems
+ part2 = parametrize_sorted(
+ similar_items + other_items[slicing_index:],
+ newignore, cache, scopenum)
+ part1 = parametrize_sorted(
+ other_items[:slicing_index], newignore,
+ cache, scopenum+1)
+ return part1 + part2
else:
- olditems = parametrize_sorted(olditems, ignore, cache, scopenum+1)
- return olditems + newitems
+ other_items = parametrize_sorted(other_items, ignore, cache, scopenum+1)
+ return other_items + similar_items
def getfuncargparams(item, ignore, scopenum, cache):
""" return list of (arg,param) tuple, sorted by broader scope first. """
@@ -1766,6 +1826,18 @@
def xunitsetup(obj, name):
meth = getattr(obj, name, None)
- if meth is not None:
- if not hasattr(meth, "_pytestfixturefunction"):
- return meth
+ if getfixturemarker(meth) is None:
+ return meth
+
+def getfixturemarker(obj):
+ """ return fixturemarker or None if it doesn't exist or raised
+ exceptions."""
+ try:
+ return getattr(obj, "_pytestfixturefunction", None)
+ except KeyboardInterrupt:
+ raise
+ except Exception:
+ # some objects raise errors like request (from flask import request)
+ # we don't expect them to be fixture functions
+ return None
+
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/runner.py
--- a/_pytest/runner.py
+++ b/_pytest/runner.py
@@ -63,12 +63,20 @@
return True
def runtestprotocol(item, log=True, nextitem=None):
+ hasrequest = hasattr(item, "_request")
+ if hasrequest and not item._request:
+ item._initrequest()
rep = call_and_report(item, "setup", log)
reports = [rep]
if rep.passed:
reports.append(call_and_report(item, "call", log))
reports.append(call_and_report(item, "teardown", log,
nextitem=nextitem))
+ # after all teardown hooks have been called
+ # want funcargs and request info to go away
+ if hasrequest:
+ item._request = False
+ item.funcargs = None
return reports
def pytest_runtest_setup(item):
@@ -190,7 +198,8 @@
if call.when == "call":
longrepr = item.repr_failure(excinfo)
else: # exception in setup or teardown
- longrepr = item._repr_failure_py(excinfo)
+ longrepr = item._repr_failure_py(excinfo,
+ style=item.config.option.tbstyle)
return TestReport(item.nodeid, item.location,
keywords, outcome, longrepr, when,
duration=duration)
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/skipping.py
--- a/_pytest/skipping.py
+++ b/_pytest/skipping.py
@@ -89,7 +89,11 @@
if isinstance(expr, py.builtin._basestring):
result = cached_eval(self.item.config, expr, d)
else:
- pytest.fail("expression is not a string")
+ if self.get("reason") is None:
+ # XXX better be checked at collection time
+ pytest.fail("you need to specify reason=STRING "
+ "when using booleans as conditions.")
+ result = bool(expr)
if result:
self.result = True
self.expr = expr
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -454,10 +454,14 @@
if val:
parts.append("%d %s" %(len(val), key))
line = ", ".join(parts)
- # XXX coloring
msg = "%s in %.2f seconds" %(line, session_duration)
if self.verbosity >= 0:
- self.write_sep("=", msg, bold=True)
+ markup = dict(bold=True)
+ if 'failed' in self.stats:
+ markup['red'] = True
+ else:
+ markup['green'] = True
+ self.write_sep("=", msg, **markup)
#else:
# self.write_line(msg, bold=True)
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/_templates/layout.html
--- a/doc/en/_templates/layout.html
+++ b/doc/en/_templates/layout.html
@@ -3,6 +3,12 @@
{% block relbaritems %}
{{ super() }}
+
+
+
+
{% endblock %}
{% block footer %}
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/_templates/localtoc.html
--- a/doc/en/_templates/localtoc.html
+++ b/doc/en/_templates/localtoc.html
@@ -31,6 +31,8 @@
issues[bb]contact
+ |
+ Talks/Posts |
{% extends "basic/localtoc.html" %}
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 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.3.5
release-2.3.4
release-2.3.3
release-2.3.2
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/announce/release-2.3.5.txt
--- a/doc/en/announce/release-2.3.5.txt
+++ b/doc/en/announce/release-2.3.5.txt
@@ -1,23 +1,61 @@
-pytest-2.3.5: bug fixes
+pytest-2.3.5: bug fixes and little improvements
===========================================================================
-pytest-2.3.5 is a bug fix release for the pytest testing tool.
-See the changelog below for details. And
+pytest-2.3.5 is a maintenance release with many bug fixes and little
+improvements. See the changelog below for details. No backward
+compatibility issues are foreseen and all plugins which worked with the
+prior version are expected to work unmodified. Speaking of which, a
+few interesting new plugins saw the light last month:
+
+- pytest-instafail: show failure information while tests are running
+- pytest-qt: testing of GUI applications written with QT/Pyside
+- pytest-xprocess: managing external processes across test runs
+- pytest-random: randomize test ordering
+
+And several others like pytest-django saw maintenance releases.
+For a more complete list, check out
+https://pypi.python.org/pypi?%3Aaction=search&term=pytest&submit=search.
+
+For general information see:
http://pytest.org/
-for general information. To install or upgrade pytest:
+To install or upgrade pytest:
pip install -U pytest # or
easy_install -U pytest
-best,
+Particular thanks to Floris, Ronny, Benjamin and the many bug reporters
+and fix providers.
+
+may the fixtures be with you,
holger krekel
Changes between 2.3.4 and 2.3.5
-----------------------------------
+- never consider a fixture function for test function collection
+
+- allow re-running of test items / helps to fix pytest-reruntests plugin
+ and also help to keep less fixture/resource references alive
+
+- put captured stdout/stderr into junitxml output even for passing tests
+ (thanks Adam Goucher)
+
+- Issue 265 - integrate nose setup/teardown with setupstate
+ so it doesnt try to teardown if it did not setup
+
+- issue 271 - dont write junitxml on slave nodes
+
+- Issue 274 - dont try to show full doctest example
+ when doctest does not know the example location
+
+- issue 280 - disable assertion rewriting on buggy CPython 2.6.0
+
+- inject "getfixture()" helper to retrieve fixtures from doctests,
+ thanks Andreas Zeidler
+
- issue 259 - when assertion rewriting, be consistent with the default
source encoding of ASCII on Python 2
@@ -26,7 +64,7 @@
- issue250 unicode/str mixes in parametrization names and values now works
- issue257, assertion-triggered compilation of source ending in a
- comment line doesn't blow up in python2.5 (fixed through py>=1.4.13)
+ comment line doesn't blow up in python2.5 (fixed through py>=1.4.13.dev6)
- fix --genscript option to generate standalone scripts that also
work with python3.3 (importer ordering)
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/assert.txt
--- a/doc/en/assert.txt
+++ b/doc/en/assert.txt
@@ -26,7 +26,7 @@
$ py.test test_assert1.py
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 1 items
test_assert1.py F
@@ -110,7 +110,7 @@
$ py.test test_assert2.py
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 1 items
test_assert2.py F
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/capture.txt
--- a/doc/en/capture.txt
+++ b/doc/en/capture.txt
@@ -64,7 +64,7 @@
$ py.test
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 2 items
test_module.py .F
@@ -78,7 +78,7 @@
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 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/conf.py
--- a/doc/en/conf.py
+++ b/doc/en/conf.py
@@ -17,7 +17,7 @@
#
# The full version, including alpha/beta/rc tags.
# The short X.Y version.
-version = release = "2.3.4.1"
+version = release = "2.3.5"
import sys, os
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 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.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 1 items
mymodule.py .
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/example/markers.txt
--- a/doc/en/example/markers.txt
+++ b/doc/en/example/markers.txt
@@ -28,7 +28,7 @@
$ py.test -v -m webtest
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4 -- /home/hpk/p/pytest/.tox/regen/bin/python
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
test_server.py:3: test_send_http PASSED
@@ -40,7 +40,7 @@
$ py.test -v -m "not webtest"
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4 -- /home/hpk/p/pytest/.tox/regen/bin/python
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
test_server.py:6: test_something_quick PASSED
@@ -61,7 +61,7 @@
$ py.test -v -k http # running with the above defined example module
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4 -- /home/hpk/p/pytest/.tox/regen/bin/python
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
test_server.py:3: test_send_http PASSED
@@ -73,7 +73,7 @@
$ py.test -k "not send_http" -v
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4 -- /home/hpk/p/pytest/.tox/regen/bin/python
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
test_server.py:6: test_something_quick PASSED
@@ -86,7 +86,7 @@
$ py.test -k "http or quick" -v
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4 -- /home/hpk/p/pytest/.tox/regen/bin/python
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
test_server.py:3: test_send_http PASSED
@@ -185,6 +185,29 @@
in which case it will be applied to all functions and
methods defined in the module.
+.. _`marking individual tests when using parametrize`:
+
+Marking individual tests when using parametrize
+-----------------------------------------------
+
+When using parametrize, applying a mark will make it apply
+to each individual test. However it is also possible to
+apply a marker to an individual test instance::
+
+ import pytest
+
+ @pytest.mark.foo
+ @pytest.mark.parametrize(("n", "expected"), [
+ (1, 2),
+ pytest.mark.bar((1, 3)),
+ (2, 3),
+ ])
+ def test_increment(n, expected):
+ assert n + 1 == expected
+
+In this example the mark "foo" will apply to each of the three
+tests, whereas the "bar" mark is only applied to the second test.
+Skip and xfail marks can also be applied in this way, see :ref:`skip/xfail with parametrize`.
.. _`adding a custom marker from a plugin`:
@@ -232,7 +255,7 @@
$ py.test -E stage2
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 1 items
test_someenv.py s
@@ -243,7 +266,7 @@
$ py.test -E stage1
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 1 items
test_someenv.py .
@@ -360,12 +383,12 @@
$ py.test -rs # this option reports skip reasons
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 4 items
test_plat.py s.s.
========================= short test summary info ==========================
- SKIP [2] /tmp/doc-exec-133/conftest.py:12: cannot run on platform linux2
+ SKIP [2] /tmp/doc-exec-273/conftest.py:12: cannot run on platform linux2
=================== 2 passed, 2 skipped in 0.01 seconds ====================
@@ -373,7 +396,7 @@
$ py.test -m linux2
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 4 items
test_plat.py .
@@ -424,7 +447,7 @@
$ py.test -m interface --tb=short
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 4 items
test_module.py FF
@@ -445,7 +468,7 @@
$ py.test -m "interface or event" --tb=short
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 4 items
test_module.py FFF
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/example/nonpython.txt
--- a/doc/en/example/nonpython.txt
+++ b/doc/en/example/nonpython.txt
@@ -27,7 +27,7 @@
nonpython $ py.test test_simple.yml
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 2 items
test_simple.yml .F
@@ -37,7 +37,7 @@
usecase execution failed
spec failed: 'some': 'other'
no further details known at this point.
- ==================== 1 failed, 1 passed in 0.09 seconds ====================
+ ==================== 1 failed, 1 passed in 0.05 seconds ====================
You get one dot for the passing ``sub1: sub1`` check and one failure.
Obviously in the above ``conftest.py`` you'll want to implement a more
@@ -56,7 +56,7 @@
nonpython $ py.test -v
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4 -- /home/hpk/p/pytest/.tox/regen/bin/python
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 2 items
test_simple.yml:1: usecase: ok PASSED
@@ -67,17 +67,17 @@
usecase execution failed
spec failed: 'some': 'other'
no further details known at this point.
- ==================== 1 failed, 1 passed in 0.04 seconds ====================
+ ==================== 1 failed, 1 passed in 0.05 seconds ====================
While developing your custom test collection and execution it's also
interesting to just look at the collection tree::
nonpython $ py.test --collectonly
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 2 items
- ============================= in 0.04 seconds =============================
+ ============================= in 0.05 seconds =============================
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/example/nonpython/conftest.py
--- a/doc/en/example/nonpython/conftest.py
+++ b/doc/en/example/nonpython/conftest.py
@@ -9,7 +9,7 @@
class YamlFile(pytest.File):
def collect(self):
import yaml # we need a yaml parser, e.g. PyYAML
- raw = yaml.load(self.fspath.open())
+ raw = yaml.safe_load(self.fspath.open())
for name, spec in raw.items():
yield YamlItem(name, self, spec)
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/example/parametrize.txt
--- a/doc/en/example/parametrize.txt
+++ b/doc/en/example/parametrize.txt
@@ -104,21 +104,19 @@
$ py.test test_scenarios.py
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.4.5dev3
- plugins: xdist, oejskit, pep8, cache, couchdbkit, quickcheck
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 4 items
test_scenarios.py ....
- ========================= 4 passed in 0.04 seconds =========================
+ ========================= 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::
$ py.test --collectonly test_scenarios.py
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.4.5dev3
- plugins: xdist, oejskit, pep8, cache, couchdbkit, quickcheck
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 4 items
@@ -128,7 +126,7 @@
- ============================= in 0.03 seconds =============================
+ ============================= in 0.01 seconds =============================
Note that we told ``metafunc.parametrize()`` that your scenario values
should be considered class-scoped. With pytest-2.3 this leads to a
@@ -182,14 +180,13 @@
$ py.test test_backends.py --collectonly
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.4.5dev3
- plugins: xdist, oejskit, pep8, cache, couchdbkit, quickcheck
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 2 items
- ============================= in 0.03 seconds =============================
+ ============================= in 0.00 seconds =============================
And then when we run the test::
@@ -198,7 +195,7 @@
================================= FAILURES =================================
_________________________ test_db_initialized[d2] __________________________
- db =
+ db =
def test_db_initialized(db):
# a dummy test
@@ -253,7 +250,7 @@
================================= FAILURES =================================
________________________ TestClass.test_equals[1-2] ________________________
- self = , a = 1, b = 2
+ self = , a = 1, b = 2
def test_equals(self, a, b):
> assert a == b
@@ -327,15 +324,14 @@
$ py.test -rs test_module.py
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.4.5dev3
- plugins: xdist, oejskit, pep8, cache, couchdbkit, quickcheck
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 2 items
test_module.py .s
========================= short test summary info ==========================
- SKIP [1] /tmp/doc-exec-11/conftest.py:10: could not import 'opt2'
+ SKIP [1] /tmp/doc-exec-275/conftest.py:10: could not import 'opt2'
- =================== 1 passed, 1 skipped in 0.04 seconds ====================
+ =================== 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:
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/example/pythoncollection.txt
--- a/doc/en/example/pythoncollection.txt
+++ b/doc/en/example/pythoncollection.txt
@@ -43,7 +43,7 @@
$ py.test --collectonly
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 2 items
@@ -82,7 +82,7 @@
. $ py.test --collectonly pythoncollection.py
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 3 items
@@ -135,7 +135,7 @@
$ py.test --collectonly
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 1 items
diff -r 25983ac76a7887522684bca6a9173d23e5adc30c -r 32065167d92882d1c3cd1c152c5a769f52e67784 doc/en/example/reportingdemo.txt
--- a/doc/en/example/reportingdemo.txt
+++ b/doc/en/example/reportingdemo.txt
@@ -13,7 +13,7 @@
assertion $ py.test failure_demo.py
=========================== test session starts ============================
- platform linux2 -- Python 2.7.3 -- pytest-2.3.4
+ platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 39 items
failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@@ -30,7 +30,7 @@
failure_demo.py:15: AssertionError
_________________________ TestFailing.test_simple __________________________
- self =
+ self =
def test_simple(self):
def f():
@@ -40,13 +40,13 @@
> 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(
@@ -66,19 +66,19 @@
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'
@@ -89,7 +89,7 @@
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'
@@ -102,7 +102,7 @@
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'
@@ -115,15 +115,15 @@
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
> assert a == b
E assert '111111111111...2222222222222' == '1111111111111...2222222222222'
- E Skipping 90 identical leading characters in diff
- E Skipping 91 identical trailing characters in diff
+ E Skipping 90 identical leading characters in diff, use -v to show
+ E Skipping 91 identical trailing characters in diff, use -v to show
E - 1111111111a222222222
E ? ^
E + 1111111111b222222222
@@ -132,15 +132,15 @@
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
> assert a == b
E assert '1\n1\n1\n1\n...n2\n2\n2\n2\n' == '1\n1\n1\n1\n1...n2\n2\n2\n2\n'
- E Skipping 190 identical leading characters in diff
- E Skipping 191 identical trailing characters in diff
+ E Skipping 190 identical leading characters in diff, use -v to show
+ E Skipping 191 identical trailing characters in diff, use -v to show
E 1
E 1
E 1
@@ -156,7 +156,7 @@
failure_demo.py:58: AssertionError
_________________ TestSpecialisedExplanations.test_eq_list _________________
- self =
+ self =
def test_eq_list(self):
> assert [0, 1, 2] == [0, 1, 3]
@@ -166,7 +166,7 @@
failure_demo.py:61: AssertionError
______________ TestSpecialisedExplanations.test_eq_list_long _______________
- self =
+ self =
def test_eq_list_long(self):
a = [0]*100 + [1] + [3]*100
@@ -178,20 +178,23 @@
failure_demo.py:66: AssertionError
_________________ TestSpecialisedExplanations.test_eq_dict _________________
- self =
+ self =
def test_eq_dict(self):
- > assert {'a': 0, 'b': 1} == {'a': 0, 'b': 2}
- E assert {'a': 0, 'b': 1} == {'a': 0, 'b': 2}
- E - {'a': 0, 'b': 1}
- E ? ^
- E + {'a': 0, 'b': 2}
- E ? ^
+ > 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}
+ E Hiding 1 identical items, use -v to show
+ E Differing items:
+ E {'b': 1} != {'b': 2}
+ E Left contains more items:
+ 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])
@@ -207,7 +210,7 @@
failure_demo.py:72: AssertionError
_____________ TestSpecialisedExplanations.test_eq_longer_list ______________
- self =
+ self =
def test_eq_longer_list(self):
> assert [1,2] == [1,2,3]
@@ -217,7 +220,7 @@
failure_demo.py:75: AssertionError
_________________ TestSpecialisedExplanations.test_in_list _________________
- self =
+ self =
def test_in_list(self):
> assert 1 in [0, 2, 3, 4, 5]
@@ -226,7 +229,7 @@
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'
@@ -244,7 +247,7 @@
failure_demo.py:82: AssertionError
___________ TestSpecialisedExplanations.test_not_in_text_single ____________
- self =
+ self =
def test_not_in_text_single(self):
text = 'single foo line'
@@ -257,7 +260,7 @@
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
@@ -270,7 +273,7 @@
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
@@ -289,7 +292,7 @@
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 __________________________
@@ -299,8 +302,8 @@
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 __________________________
@@ -316,7 +319,7 @@
failure_demo.py:116:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
- self =
+ self =
def _get_b(self):
> raise Exception('Failed to get attrib')
@@ -332,15 +335,15 @@
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'
@@ -352,10 +355,10 @@
> int(s)
E ValueError: invalid literal for int() with base 10: 'qwe'
- <0-codegen /home/hpk/p/pytest/.tox/regen/lib/python2.7/site-packages/_pytest/python.py:851>:1: ValueError
+ <0-codegen /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:858>:1: ValueError
______________________ TestRaises.test_raises_doesnt _______________________
- self =
+ self =
def test_raises_doesnt(self):
> raises(IOError, "int('3')")
@@ -364,7 +367,7 @@
failure_demo.py:136: Failed
__________________________ TestRaises.test_raise ___________________________
- self =
+ self =
def test_raise(self):
> raise ValueError("demo error")
@@ -373,7 +376,7 @@
failure_demo.py:139: ValueError
________________________ TestRaises.test_tupleerror ________________________
- self =
+ self =
def test_tupleerror(self):
> a,b = [1]
@@ -382,7 +385,7 @@
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]
@@ -395,7 +398,7 @@
l is [1, 2, 3]
________________________ TestRaises.test_some_error ________________________
- self =
+ self =
def test_some_error(self):
> if namenotexi:
@@ -423,7 +426,7 @@
<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():
@@ -452,7 +455,7 @@
failure_demo.py:5: AssertionError
___________________ TestMoreErrors.test_z1_unpack_error ____________________
- self =
+ self =
def test_z1_unpack_error(self):
l = []
@@ -462,7 +465,7 @@
failure_demo.py:179: ValueError
____________________ TestMoreErrors.test_z2_type_error _____________________
- self =
+ self =
def test_z2_type_error(self):
l = 3
@@ -472,19 +475,19 @@
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():
@@ -492,15 +495,15 @@
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)
@@ -510,18 +513,18 @@
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
@@ -531,7 +534,7 @@
failure_demo.py:205: AssertionError
_____________________ TestMoreErrors.test_try_finally ______________________
- self =
+ self =
def test_try_finally(self):
x = 1
@@ -540,4 +543,4 @@
E assert 1 == 0
failure_demo.py:210: AssertionError
- ======================== 39 failed in 0.25 seconds =========================
+ ======================== 39 failed in 0.21 seconds =========================
This diff is so big that we needed to truncate the remainder.
https://bitbucket.org/hpk42/pytest/commits/a706f6fd5fc7/
Changeset: a706f6fd5fc7
User: bubenkoff
Date: 2013-07-06 10:26:14
Summary: remove unnecessary print
Affected #: 1 file
diff -r 32065167d92882d1c3cd1c152c5a769f52e67784 -r a706f6fd5fc7fd1bacc50c1ce22b99dc4ca06284 testing/test_conftest.py
--- a/testing/test_conftest.py
+++ b/testing/test_conftest.py
@@ -211,7 +211,6 @@
ct2 = sub.join("conftest.py")
ct2.write("")
def impct(p):
- print p
return p
conftest = Conftest()
monkeypatch.setattr(conftest, 'importconftest', impct)
https://bitbucket.org/hpk42/pytest/commits/9d60521c1e64/
Changeset: 9d60521c1e64
User: flub
Date: 2013-07-06 11:00:29
Summary: Mention issue 300 in changelog
Affected #: 1 file
diff -r a706f6fd5fc7fd1bacc50c1ce22b99dc4ca06284 -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
Changes between 2.3.5 and 2.4.DEV
-----------------------------------
+- fix issue300 - Fix order of conftest loading when starting py.test
+ in a subdirectory.
+
- fix issue323 - sorting of many module-scoped arg parametrizations
- add support for setUpModule/tearDownModule detection, thanks Brian Okken.
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 Jul 6 16:03:28 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Sat, 06 Jul 2013 14:03:28 -0000
Subject: [Pytest-commit] commit/pytest: 3 new changesets
Message-ID: <20130706140328.1712.29691@bitbucket20.managed.contegix.com>
3 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/bca2dc5e59dd/
Changeset: bca2dc5e59dd
User: katarzynaanna
Date: 2013-07-06 15:43:59
Summary: improved reporting
added intermediate level of quiet reporting:
* -q now shows short summary (# passed/failed tests + time)
* the former -q is now -qq
Affected #: 2 files
diff -r 29461bb5660a9c38aed9a8762401afa8f9188149 -r bca2dc5e59ddfe825771be634a74bf79598bcd5e _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -44,7 +44,7 @@
pass
else:
config._cleanup.append(lambda: newstdout.close())
- assert stdout.encoding == newstdout.encoding
+ assert stdout.encoding == newstdout.encoding
stdout = newstdout
reporter = TerminalReporter(config, stdout)
@@ -105,7 +105,7 @@
self.hasmarkup = self._tw.hasmarkup
def hasopt(self, char):
- char = {'xfailed': 'x', 'skipped': 's'}.get(char,char)
+ char = {'xfailed': 'x', 'skipped': 's'}.get(char, char)
return char in self.reportchars
def write_fspath_result(self, fspath, res):
@@ -154,7 +154,7 @@
def pytest_plugin_registered(self, plugin):
if self.config.option.traceconfig:
- msg = "PLUGIN registered: %s" %(plugin,)
+ msg = "PLUGIN registered: %s" % (plugin,)
# XXX this event may happen during setup/teardown time
# which unfortunately captures our output here
# which garbles our output if we use self.write_line
@@ -209,7 +209,7 @@
self.currentfspath = -2
def pytest_collection(self):
- if not self.hasmarkup and self.config.option.verbose >=1:
+ if not self.hasmarkup and self.config.option.verbose >= 1:
self.write("collecting ... ", bold=True)
def pytest_collectreport(self, report):
@@ -325,8 +325,8 @@
stack.append(col)
#if col.name == "()":
# continue
- indent = (len(stack)-1) * " "
- self._tw.line("%s%s" %(indent, col))
+ indent = (len(stack) - 1) * " "
+ self._tw.line("%s%s" % (indent, col))
def pytest_sessionfinish(self, exitstatus, __multicall__):
__multicall__.execute()
@@ -452,9 +452,9 @@
if key: # setup/teardown reports have an empty key, ignore them
val = self.stats.get(key, None)
if val:
- parts.append("%d %s" %(len(val), key))
+ parts.append("%d %s" % (len(val), key))
line = ", ".join(parts)
- msg = "%s in %.2f seconds" %(line, session_duration)
+ msg = "%s in %.2f seconds" % (line, session_duration)
if self.verbosity >= 0:
markup = dict(bold=True)
if 'failed' in self.stats:
@@ -462,6 +462,10 @@
else:
markup['green'] = True
self.write_sep("=", msg, **markup)
+ if self.verbosity == -1:
+ if line:
+ self.write("%s, " % line)
+ self.write("time: %.2f seconds\n" % session_duration)
#else:
# self.write_line(msg, bold=True)
@@ -475,7 +479,7 @@
if m:
l.append("-m %r" % m)
if l:
- self.write_sep("=", "%d tests deselected by %r" %(
+ self.write_sep("=", "%d tests deselected by %r" % (
len(self.stats['deselected']), " ".join(l)), bold=True)
def repr_pythonversion(v=None):
diff -r 29461bb5660a9c38aed9a8762401afa8f9188149 -r bca2dc5e59ddfe825771be634a74bf79598bcd5e testing/test_terminal.py
--- a/testing/test_terminal.py
+++ b/testing/test_terminal.py
@@ -1,7 +1,7 @@
"""
terminal reporting of the full testing process.
"""
-import pytest,py
+import pytest, py
import sys
from _pytest.terminal import TerminalReporter, repr_pythonversion, getreportopt
@@ -32,7 +32,7 @@
metafunc.addcall(id="verbose",
funcargs={'option': Option(verbose=True)})
metafunc.addcall(id="quiet",
- funcargs={'option': Option(verbose=-1)})
+ funcargs={'option': Option(verbose= -1)})
metafunc.addcall(id="fulltrace",
funcargs={'option': Option(fulltrace=True)})
@@ -286,7 +286,7 @@
try:
monkeypatch.setattr(sys, 'version_info', (2, 5, 1, 'final', 0))
assert repr_pythonversion() == "2.5.1-final-0"
- py.std.sys.version_info = x = (2,3)
+ py.std.sys.version_info = x = (2, 3)
assert repr_pythonversion() == str(x)
finally:
monkeypatch.undo() # do this early as pytest can get confused
@@ -411,7 +411,7 @@
verinfo = ".".join(map(str, py.std.sys.version_info[:3]))
result.stdout.fnmatch_lines([
"*===== test session starts ====*",
- "platform %s -- Python %s*" %(
+ "platform %s -- Python %s*" % (
py.std.sys.platform, verinfo), # , py.std.sys.executable),
"*test_header_trailer_info.py .",
"=* 1 passed in *.[0-9][0-9] seconds *=",
@@ -473,6 +473,17 @@
assert 'test session starts' not in s
assert p1.basename not in s
assert "===" not in s
+ assert "passed" in s
+
+ def test_more_quiet_reporting(self, testdir):
+ p1 = testdir.makepyfile("def test_pass(): pass")
+ result = testdir.runpytest(p1, '-qq')
+ s = result.stdout.str()
+ assert 'test session starts' not in s
+ assert p1.basename not in s
+ assert "===" not in s
+ assert "passed" not in s
+
def test_fail_extra_reporting(testdir):
p = testdir.makepyfile("def test_this(): assert 0")
@@ -679,5 +690,5 @@
""")
result = testdir.runpytest("--tb=native")
result.stdout.fnmatch_lines([
- '*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*'
+ '*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*'
])
https://bitbucket.org/hpk42/pytest/commits/71ae07462c66/
Changeset: 71ae07462c66
User: katarzynaanna
Date: 2013-07-06 15:54:33
Summary: merge
Affected #: 5 files
diff -r bca2dc5e59ddfe825771be634a74bf79598bcd5e -r 71ae07462c66ccea05901442fb0461d7834aea1d CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
Changes between 2.3.5 and 2.4.DEV
-----------------------------------
+- fix issue300 - Fix order of conftest loading when starting py.test
+ in a subdirectory.
+
- fix issue323 - sorting of many module-scoped arg parametrizations
- add support for setUpModule/tearDownModule detection, thanks Brian Okken.
diff -r bca2dc5e59ddfe825771be634a74bf79598bcd5e -r 71ae07462c66ccea05901442fb0461d7834aea1d _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -196,27 +196,20 @@
self.getconftestmodules(x)
def getconftestmodules(self, path):
- """ return a list of imported conftest modules for the given path. """
try:
clist = self._path2confmods[path]
except KeyError:
if path is None:
- raise ValueError("missing default confest.")
- dp = path.dirpath()
+ raise ValueError("missing default conftest.")
clist = []
- if dp != path:
- cutdir = self._confcutdir
- if cutdir and path != cutdir and not path.relto(cutdir):
- pass
- else:
- conftestpath = path.join("conftest.py")
- if conftestpath.check(file=1):
- clist.append(self.importconftest(conftestpath))
- clist[:0] = self.getconftestmodules(dp)
+ for parent in path.parts():
+ if self._confcutdir and self._confcutdir.relto(parent):
+ continue
+ conftestpath = parent.join("conftest.py")
+ if conftestpath.check(file=1):
+ clist.append(self.importconftest(conftestpath))
self._path2confmods[path] = clist
- # be defensive: avoid changes from caller side to
- # affect us by always returning a copy of the actual list
- return clist[:]
+ return clist
def rget(self, name, path=None):
mod, value = self.rget_with_confmod(name, path)
diff -r bca2dc5e59ddfe825771be634a74bf79598bcd5e -r 71ae07462c66ccea05901442fb0461d7834aea1d testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -102,6 +102,77 @@
"*2 passed*"
])
+ def test_extend_fixture_module_class(self, testdir):
+ testfile = testdir.makepyfile("""
+ import pytest
+
+ @pytest.fixture
+ def spam():
+ return 'spam'
+
+ class TestSpam:
+
+ @pytest.fixture
+ def spam(self, spam):
+ return spam * 2
+
+ def test_spam(self, spam):
+ assert spam == 'spamspam'
+ """)
+ result = testdir.runpytest()
+ result.stdout.fnmatch_lines(["*1 passed*"])
+ result = testdir.runpytest(testfile)
+ result.stdout.fnmatch_lines(["*1 passed*"])
+
+ def test_extend_fixture_conftest_module(self, testdir):
+ testdir.makeconftest("""
+ import pytest
+
+ @pytest.fixture
+ def spam():
+ return 'spam'
+ """)
+ testfile = testdir.makepyfile("""
+ import pytest
+
+ @pytest.fixture
+ def spam(spam):
+ return spam * 2
+
+ def test_spam(spam):
+ assert spam == 'spamspam'
+ """)
+ result = testdir.runpytest()
+ result.stdout.fnmatch_lines(["*1 passed*"])
+ result = testdir.runpytest(testfile)
+ result.stdout.fnmatch_lines(["*1 passed*"])
+
+ def test_extend_fixture_conftest_conftest(self, testdir):
+ testdir.makeconftest("""
+ import pytest
+
+ @pytest.fixture
+ def spam():
+ return 'spam'
+ """)
+ pkg = testdir.mkpydir("pkg")
+ pkg.join("conftest.py").write(py.code.Source("""
+ import pytest
+
+ @pytest.fixture
+ def spam(spam):
+ return spam * 2
+ """))
+ testfile = pkg.join("test_spam.py")
+ testfile.write(py.code.Source("""
+ def test_spam(spam):
+ assert spam == "spamspam"
+ """))
+ result = testdir.runpytest()
+ result.stdout.fnmatch_lines(["*1 passed*"])
+ result = testdir.runpytest(testfile)
+ result.stdout.fnmatch_lines(["*1 passed*"])
+
def test_funcarg_lookup_error(self, testdir):
p = testdir.makepyfile("""
def test_lookup_error(unknown):
diff -r bca2dc5e59ddfe825771be634a74bf79598bcd5e -r 71ae07462c66ccea05901442fb0461d7834aea1d testing/test_conftest.py
--- a/testing/test_conftest.py
+++ b/testing/test_conftest.py
@@ -204,3 +204,14 @@
"""))
result = testdir.runpytest("-h", "--confcutdir=%s" % x, x)
result.stdout.fnmatch_lines(["*--xyz*"])
+
+def test_conftest_import_order(testdir, monkeypatch):
+ ct1 = testdir.makeconftest("")
+ sub = testdir.mkdir("sub")
+ ct2 = sub.join("conftest.py")
+ ct2.write("")
+ def impct(p):
+ return p
+ conftest = Conftest()
+ monkeypatch.setattr(conftest, 'importconftest', impct)
+ assert conftest.getconftestmodules(sub) == [ct1, ct2]
diff -r bca2dc5e59ddfe825771be634a74bf79598bcd5e -r 71ae07462c66ccea05901442fb0461d7834aea1d testing/test_terminal.py
--- a/testing/test_terminal.py
+++ b/testing/test_terminal.py
@@ -654,9 +654,9 @@
""")
result = testdir.runpytest("a")
result.stdout.fnmatch_lines([
+ "*hello: 42*",
"line1",
str(testdir.tmpdir),
- "*hello: 42*",
])
@pytest.mark.xfail("not hasattr(os, 'dup')")
https://bitbucket.org/hpk42/pytest/commits/c1bf2cd59fb7/
Changeset: c1bf2cd59fb7
User: hpk42
Date: 2013-07-06 16:03:27
Summary: Merged in katarzynaanna/pytest (pull request #42)
Improved reporting
Affected #: 2 files
diff -r c3a0a8895e55c89070142e3849959464d08514b6 -r c1bf2cd59fb7accc4835ff34ca8551b1155a1ae2 _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -44,7 +44,7 @@
pass
else:
config._cleanup.append(lambda: newstdout.close())
- assert stdout.encoding == newstdout.encoding
+ assert stdout.encoding == newstdout.encoding
stdout = newstdout
reporter = TerminalReporter(config, stdout)
@@ -105,7 +105,7 @@
self.hasmarkup = self._tw.hasmarkup
def hasopt(self, char):
- char = {'xfailed': 'x', 'skipped': 's'}.get(char,char)
+ char = {'xfailed': 'x', 'skipped': 's'}.get(char, char)
return char in self.reportchars
def write_fspath_result(self, fspath, res):
@@ -154,7 +154,7 @@
def pytest_plugin_registered(self, plugin):
if self.config.option.traceconfig:
- msg = "PLUGIN registered: %s" %(plugin,)
+ msg = "PLUGIN registered: %s" % (plugin,)
# XXX this event may happen during setup/teardown time
# which unfortunately captures our output here
# which garbles our output if we use self.write_line
@@ -209,7 +209,7 @@
self.currentfspath = -2
def pytest_collection(self):
- if not self.hasmarkup and self.config.option.verbose >=1:
+ if not self.hasmarkup and self.config.option.verbose >= 1:
self.write("collecting ... ", bold=True)
def pytest_collectreport(self, report):
@@ -325,8 +325,8 @@
stack.append(col)
#if col.name == "()":
# continue
- indent = (len(stack)-1) * " "
- self._tw.line("%s%s" %(indent, col))
+ indent = (len(stack) - 1) * " "
+ self._tw.line("%s%s" % (indent, col))
def pytest_sessionfinish(self, exitstatus, __multicall__):
__multicall__.execute()
@@ -452,9 +452,9 @@
if key: # setup/teardown reports have an empty key, ignore them
val = self.stats.get(key, None)
if val:
- parts.append("%d %s" %(len(val), key))
+ parts.append("%d %s" % (len(val), key))
line = ", ".join(parts)
- msg = "%s in %.2f seconds" %(line, session_duration)
+ msg = "%s in %.2f seconds" % (line, session_duration)
if self.verbosity >= 0:
markup = dict(bold=True)
if 'failed' in self.stats:
@@ -462,6 +462,10 @@
else:
markup['green'] = True
self.write_sep("=", msg, **markup)
+ if self.verbosity == -1:
+ if line:
+ self.write("%s, " % line)
+ self.write("time: %.2f seconds\n" % session_duration)
#else:
# self.write_line(msg, bold=True)
@@ -475,7 +479,7 @@
if m:
l.append("-m %r" % m)
if l:
- self.write_sep("=", "%d tests deselected by %r" %(
+ self.write_sep("=", "%d tests deselected by %r" % (
len(self.stats['deselected']), " ".join(l)), bold=True)
def repr_pythonversion(v=None):
diff -r c3a0a8895e55c89070142e3849959464d08514b6 -r c1bf2cd59fb7accc4835ff34ca8551b1155a1ae2 testing/test_terminal.py
--- a/testing/test_terminal.py
+++ b/testing/test_terminal.py
@@ -1,7 +1,7 @@
"""
terminal reporting of the full testing process.
"""
-import pytest,py
+import pytest, py
import sys
from _pytest.terminal import TerminalReporter, repr_pythonversion, getreportopt
@@ -32,7 +32,7 @@
metafunc.addcall(id="verbose",
funcargs={'option': Option(verbose=True)})
metafunc.addcall(id="quiet",
- funcargs={'option': Option(verbose=-1)})
+ funcargs={'option': Option(verbose= -1)})
metafunc.addcall(id="fulltrace",
funcargs={'option': Option(fulltrace=True)})
@@ -286,7 +286,7 @@
try:
monkeypatch.setattr(sys, 'version_info', (2, 5, 1, 'final', 0))
assert repr_pythonversion() == "2.5.1-final-0"
- py.std.sys.version_info = x = (2,3)
+ py.std.sys.version_info = x = (2, 3)
assert repr_pythonversion() == str(x)
finally:
monkeypatch.undo() # do this early as pytest can get confused
@@ -411,7 +411,7 @@
verinfo = ".".join(map(str, py.std.sys.version_info[:3]))
result.stdout.fnmatch_lines([
"*===== test session starts ====*",
- "platform %s -- Python %s*" %(
+ "platform %s -- Python %s*" % (
py.std.sys.platform, verinfo), # , py.std.sys.executable),
"*test_header_trailer_info.py .",
"=* 1 passed in *.[0-9][0-9] seconds *=",
@@ -473,6 +473,17 @@
assert 'test session starts' not in s
assert p1.basename not in s
assert "===" not in s
+ assert "passed" in s
+
+ def test_more_quiet_reporting(self, testdir):
+ p1 = testdir.makepyfile("def test_pass(): pass")
+ result = testdir.runpytest(p1, '-qq')
+ s = result.stdout.str()
+ assert 'test session starts' not in s
+ assert p1.basename not in s
+ assert "===" not in s
+ assert "passed" not in s
+
def test_fail_extra_reporting(testdir):
p = testdir.makepyfile("def test_this(): assert 0")
@@ -679,5 +690,5 @@
""")
result = testdir.runpytest("--tb=native")
result.stdout.fnmatch_lines([
- '*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*'
+ '*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*'
])
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 Jul 6 16:04:28 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Sat, 06 Jul 2013 14:04:28 -0000
Subject: [Pytest-commit] commit/pytest: 2 new changesets
Message-ID: <20130706140428.1819.50274@bitbucket25.managed.contegix.com>
2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/52b615fe1946/
Changeset: 52b615fe1946
User: hpk42
Date: 2013-07-06 15:38:40
Summary: move to development doc target
Affected #: 2 files
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r 52b615fe194684a209c2d68f4dc9d998bdb9a9e5 doc/en/Makefile
--- a/doc/en/Makefile
+++ b/doc/en/Makefile
@@ -12,7 +12,7 @@
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-SITETARGET=latest
+SITETARGET=dev
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
diff -r 9d60521c1e64ed81ba7bd40a241e7a631282cc7e -r 52b615fe194684a209c2d68f4dc9d998bdb9a9e5 doc/en/conf.py
--- a/doc/en/conf.py
+++ b/doc/en/conf.py
@@ -17,7 +17,7 @@
#
# The full version, including alpha/beta/rc tags.
# The short X.Y version.
-version = release = "2.3.5"
+version = release = "2.4.0.dev"
import sys, os
https://bitbucket.org/hpk42/pytest/commits/16e79a864e96/
Changeset: 16e79a864e96
User: hpk42
Date: 2013-07-06 16:03:48
Summary: merge
Affected #: 6 files
diff -r 52b615fe194684a209c2d68f4dc9d998bdb9a9e5 -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 .gitignore
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+# Automatically generated by `hgimportsvn`
+.svn
+.hgsvn
+
+# Ignore local virtualenvs
+lib/
+bin/
+include/
+.Python/
+
+# These lines are suggested according to the svn:ignore property
+# Feel free to enable them by uncommenting them
+*.pyc
+*.pyo
+*.swp
+*.html
+*.class
+*.orig
+*~
+
+doc/*/_build
+build/
+dist/
+*.egg-info
+issue/
+env/
+3rdparty/
+.tox
+.cache
+.coverage
+.ropeproject
+
diff -r 52b615fe194684a209c2d68f4dc9d998bdb9a9e5 -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 .travis.yml
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,10 @@
+language: python
+# command to install dependencies
+install: "pip install -e . detox"
+# # command to run tests
+script: detox --recreate
+notifications:
+ irc:
+ - "chat.freenode.net#pylib"
+ email:
+ - pytest-commit at python.org
diff -r 52b615fe194684a209c2d68f4dc9d998bdb9a9e5 -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 README.rst
--- a/README.rst
+++ b/README.rst
@@ -16,6 +16,9 @@
- many `external plugins `_.
+.. image:: https://secure.travis-ci.org/bubenkoff/pytest.png?branch=travis-integration
+ :target: http://travis-ci.org/bubenkoff/pytest
+
A simple example for a test::
# content of test_module.py
diff -r 52b615fe194684a209c2d68f4dc9d998bdb9a9e5 -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -44,7 +44,7 @@
pass
else:
config._cleanup.append(lambda: newstdout.close())
- assert stdout.encoding == newstdout.encoding
+ assert stdout.encoding == newstdout.encoding
stdout = newstdout
reporter = TerminalReporter(config, stdout)
@@ -105,7 +105,7 @@
self.hasmarkup = self._tw.hasmarkup
def hasopt(self, char):
- char = {'xfailed': 'x', 'skipped': 's'}.get(char,char)
+ char = {'xfailed': 'x', 'skipped': 's'}.get(char, char)
return char in self.reportchars
def write_fspath_result(self, fspath, res):
@@ -154,7 +154,7 @@
def pytest_plugin_registered(self, plugin):
if self.config.option.traceconfig:
- msg = "PLUGIN registered: %s" %(plugin,)
+ msg = "PLUGIN registered: %s" % (plugin,)
# XXX this event may happen during setup/teardown time
# which unfortunately captures our output here
# which garbles our output if we use self.write_line
@@ -209,7 +209,7 @@
self.currentfspath = -2
def pytest_collection(self):
- if not self.hasmarkup and self.config.option.verbose >=1:
+ if not self.hasmarkup and self.config.option.verbose >= 1:
self.write("collecting ... ", bold=True)
def pytest_collectreport(self, report):
@@ -325,8 +325,8 @@
stack.append(col)
#if col.name == "()":
# continue
- indent = (len(stack)-1) * " "
- self._tw.line("%s%s" %(indent, col))
+ indent = (len(stack) - 1) * " "
+ self._tw.line("%s%s" % (indent, col))
def pytest_sessionfinish(self, exitstatus, __multicall__):
__multicall__.execute()
@@ -452,9 +452,9 @@
if key: # setup/teardown reports have an empty key, ignore them
val = self.stats.get(key, None)
if val:
- parts.append("%d %s" %(len(val), key))
+ parts.append("%d %s" % (len(val), key))
line = ", ".join(parts)
- msg = "%s in %.2f seconds" %(line, session_duration)
+ msg = "%s in %.2f seconds" % (line, session_duration)
if self.verbosity >= 0:
markup = dict(bold=True)
if 'failed' in self.stats:
@@ -462,6 +462,10 @@
else:
markup['green'] = True
self.write_sep("=", msg, **markup)
+ if self.verbosity == -1:
+ if line:
+ self.write("%s, " % line)
+ self.write("time: %.2f seconds\n" % session_duration)
#else:
# self.write_line(msg, bold=True)
@@ -475,7 +479,7 @@
if m:
l.append("-m %r" % m)
if l:
- self.write_sep("=", "%d tests deselected by %r" %(
+ self.write_sep("=", "%d tests deselected by %r" % (
len(self.stats['deselected']), " ".join(l)), bold=True)
def repr_pythonversion(v=None):
diff -r 52b615fe194684a209c2d68f4dc9d998bdb9a9e5 -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 testing/test_terminal.py
--- a/testing/test_terminal.py
+++ b/testing/test_terminal.py
@@ -1,7 +1,7 @@
"""
terminal reporting of the full testing process.
"""
-import pytest,py
+import pytest, py
import sys
from _pytest.terminal import TerminalReporter, repr_pythonversion, getreportopt
@@ -32,7 +32,7 @@
metafunc.addcall(id="verbose",
funcargs={'option': Option(verbose=True)})
metafunc.addcall(id="quiet",
- funcargs={'option': Option(verbose=-1)})
+ funcargs={'option': Option(verbose= -1)})
metafunc.addcall(id="fulltrace",
funcargs={'option': Option(fulltrace=True)})
@@ -286,7 +286,7 @@
try:
monkeypatch.setattr(sys, 'version_info', (2, 5, 1, 'final', 0))
assert repr_pythonversion() == "2.5.1-final-0"
- py.std.sys.version_info = x = (2,3)
+ py.std.sys.version_info = x = (2, 3)
assert repr_pythonversion() == str(x)
finally:
monkeypatch.undo() # do this early as pytest can get confused
@@ -411,7 +411,7 @@
verinfo = ".".join(map(str, py.std.sys.version_info[:3]))
result.stdout.fnmatch_lines([
"*===== test session starts ====*",
- "platform %s -- Python %s*" %(
+ "platform %s -- Python %s*" % (
py.std.sys.platform, verinfo), # , py.std.sys.executable),
"*test_header_trailer_info.py .",
"=* 1 passed in *.[0-9][0-9] seconds *=",
@@ -473,6 +473,17 @@
assert 'test session starts' not in s
assert p1.basename not in s
assert "===" not in s
+ assert "passed" in s
+
+ def test_more_quiet_reporting(self, testdir):
+ p1 = testdir.makepyfile("def test_pass(): pass")
+ result = testdir.runpytest(p1, '-qq')
+ s = result.stdout.str()
+ assert 'test session starts' not in s
+ assert p1.basename not in s
+ assert "===" not in s
+ assert "passed" not in s
+
def test_fail_extra_reporting(testdir):
p = testdir.makepyfile("def test_this(): assert 0")
@@ -679,5 +690,5 @@
""")
result = testdir.runpytest("--tb=native")
result.stdout.fnmatch_lines([
- '*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*'
+ '*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*'
])
diff -r 52b615fe194684a209c2d68f4dc9d998bdb9a9e5 -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -13,6 +13,10 @@
changedir=.
commands= py.test --genscript=pytest1
+[testenv:py25]
+setenv =
+ PIP_INSECURE=1
+
[testenv:py27-xdist]
changedir=.
basepython=python2.7
@@ -29,6 +33,7 @@
deps=pytest-xdist
setenv=
PYTHONDONTWRITEBYTECODE=1
+distribute=true
commands=
py.test -n3 -rfsxX \
--junitxml={envlogdir}/junit-{envname}.xml {posargs:testing}
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 Jul 6 17:07:58 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Sat, 06 Jul 2013 15:07:58 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: add kasia to changelog
Message-ID: <20130706150758.9310.38600@bitbucket04.managed.contegix.com>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/a34f61f77b84/
Changeset: a34f61f77b84
User: hpk42
Date: 2013-07-06 17:06:51
Summary: add kasia to changelog
Affected #: 1 file
diff -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 -r a34f61f77b84b72e79cc7392451418204728d447 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
Changes between 2.3.5 and 2.4.DEV
-----------------------------------
+- you can specify "-q" or "-qq" to get different levels of "quieter"
+ reporting (thanks Katarzyna Jachim)
+
- fix issue300 - Fix order of conftest loading when starting py.test
in a subdirectory.
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 Jul 6 17:17:09 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Sat, 06 Jul 2013 15:17:09 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: add KAsia to authors
Message-ID: <20130706151709.18668.56249@bitbucket15.managed.contegix.com>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/63b5f85e68df/
Changeset: 63b5f85e68df
User: hpk42
Date: 2013-07-06 17:17:03
Summary: add KAsia to authors
Affected #: 1 file
diff -r a34f61f77b84b72e79cc7392451418204728d447 -r 63b5f85e68df7242019300937e01d247f89e9361 AUTHORS
--- a/AUTHORS
+++ b/AUTHORS
@@ -31,3 +31,5 @@
Graham Horler
Andreas Zeidler
Brian Okken
+Katarzyna Jachim
+
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 Jul 6 18:58:40 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Sat, 06 Jul 2013 16:58:40 -0000
Subject: [Pytest-commit] commit/pytest: 2 new changesets
Message-ID: <20130706165840.13131.25082@bitbucket03.managed.contegix.com>
2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/a59fa6c971ab/
Changeset: a59fa6c971ab
User: flub
Date: 2013-07-06 17:56:54
Summary: Solve fixture ordering when loading plugins from conftest
Conftests are plugins with a location attached to them while other
plugins do not have a location. When ordering fixturedefs those from
plugins without a location need to be listed first.
Affected #: 2 files
diff -r 63b5f85e68df7242019300937e01d247f89e9361 -r a59fa6c971abd42810301100464c4da7bc363e1d _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -1472,8 +1472,7 @@
def pytest_plugin_registered(self, plugin):
if plugin in self._seenplugins:
return
- #print "plugin_registered", plugin
- nodeid = ""
+ nodeid = None
try:
p = py.path.local(plugin.__file__)
except AttributeError:
@@ -1580,8 +1579,8 @@
for fin in reversed(l):
fin()
- def parsefactories(self, node_or_obj, nodeid=None, unittest=False):
- if nodeid is not None:
+ def parsefactories(self, node_or_obj, nodeid=_dummy, unittest=False):
+ if nodeid is not _dummy:
holderobj = node_or_obj
else:
holderobj = node_or_obj.obj
@@ -1612,7 +1611,15 @@
marker.scope, marker.params,
unittest=unittest)
faclist = self._arg2fixturedefs.setdefault(name, [])
- faclist.append(fixturedef)
+ if not fixturedef.has_location:
+ # All Nones are at the front so this inserts the
+ # current fixturedef after the existing fixturedefs
+ # from external plugins but before the fixturedefs
+ # provided in conftests.
+ i = faclist.count(None)
+ else:
+ i = len(faclist) # append
+ faclist.insert(i, fixturedef)
if marker.autouse:
autousenames.append(name)
if autousenames:
@@ -1670,7 +1677,8 @@
def __init__(self, fixturemanager, baseid, argname, func, scope, params,
unittest=False):
self._fixturemanager = fixturemanager
- self.baseid = baseid
+ self.baseid = baseid or ''
+ self.has_location = baseid is not None
self.func = func
self.argname = argname
self.scope = scope
@@ -1721,7 +1729,8 @@
return result
def __repr__(self):
- return "" % (self.argname, self.scope)
+ return ("" %
+ (self.argname, self.scope, self.baseid, self.func.__module__))
def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames
diff -r 63b5f85e68df7242019300937e01d247f89e9361 -r a59fa6c971abd42810301100464c4da7bc363e1d testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -173,6 +173,31 @@
result = testdir.runpytest(testfile)
result.stdout.fnmatch_lines(["*1 passed*"])
+ def test_extend_fixture_conftest_plugin(request, testdir):
+ testdir.makepyfile(testplugin="""
+ import pytest
+
+ @pytest.fixture
+ def foo():
+ return 7
+ """)
+ testdir.syspathinsert()
+ testdir.makeconftest("""
+ import pytest
+
+ pytest_plugins = 'testplugin'
+
+ @pytest.fixture
+ def foo(foo):
+ return foo + 7
+ """)
+ testdir.makepyfile("""
+ def test_foo(foo):
+ assert foo == 14
+ """)
+ result = testdir.runpytest('-s')
+ assert result.ret == 0
+
def test_funcarg_lookup_error(self, testdir):
p = testdir.makepyfile("""
def test_lookup_error(unknown):
https://bitbucket.org/hpk42/pytest/commits/cc8871c02a5e/
Changeset: cc8871c02a5e
User: flub
Date: 2013-07-06 18:53:26
Summary: Always check for both ENOENT and ENOTDIR
This fixes issue 326.
Affected #: 1 file
diff -r a59fa6c971abd42810301100464c4da7bc363e1d -r cc8871c02a5e4e34ad8e42121ffefb0651304b67 _pytest/assertion/rewrite.py
--- a/_pytest/assertion/rewrite.py
+++ b/_pytest/assertion/rewrite.py
@@ -15,12 +15,6 @@
from _pytest.assertion import util
-# Windows gives ENOENT in places *nix gives ENOTDIR.
-if sys.platform.startswith("win"):
- PATH_COMPONENT_NOT_DIR = errno.ENOENT
-else:
- PATH_COMPONENT_NOT_DIR = errno.ENOTDIR
-
# py.test caches rewritten pycs in __pycache__.
if hasattr(imp, "get_tag"):
PYTEST_TAG = imp.get_tag() + "-PYTEST"
@@ -119,7 +113,7 @@
# common case) or it's blocked by a non-dir node. In the
# latter case, we'll ignore it in _write_pyc.
pass
- elif e == PATH_COMPONENT_NOT_DIR:
+ elif e in [errno.ENOENT, errno.ENOTDIR]:
# One of the path components was not a directory, likely
# because we're in a zip file.
write = False
@@ -173,7 +167,7 @@
fp = open(pyc, "wb")
except IOError:
err = sys.exc_info()[1].errno
- if err == PATH_COMPONENT_NOT_DIR:
+ if err in [errno.ENOENT, errno.ENOTDIR]:
# This happens when we get a EEXIST in find_module creating the
# __pycache__ directory and __pycache__ is by some non-dir node.
return False
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 Jul 6 20:13:29 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Sat, 06 Jul 2013 18:13:29 -0000
Subject: [Pytest-commit] commit/pytest: 2 new changesets
Message-ID: <20130706181329.26548.34290@bitbucket02.managed.contegix.com>
2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/af665883e9f2/
Changeset: af665883e9f2
Branch: 329-skipif-requires-expression-as-a-string
User: bubenkoff
Date: 2013-07-06 18:54:24
Summary: re #329 add test for skipif failure when you pass boolean without the reason. add emphasize to the docs.
Affected #: 2 files
diff -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 -r af665883e9f2f79a4c4c06580f4aeaf2cb5bfdda doc/en/skipping.txt
--- a/doc/en/skipping.txt
+++ b/doc/en/skipping.txt
@@ -10,11 +10,11 @@
may call helper functions during execution of setup or test functions.
A *skip* means that you expect your test to pass unless the environment
-(e.g. wrong Python interpreter, missing dependency) prevents it to run.
+(e.g. wrong Python interpreter, missing dependency) prevents it to run.
And *xfail* means that your test can run but you expect it to fail
because there is an implementation problem.
-py.test counts and lists *skip* and *xfail* tests separately. Detailed
+py.test counts and lists *skip* and *xfail* tests separately. Detailed
information about skipped/xfailed tests is not shown by default to avoid
cluttering the output. You can use the ``-r`` option to see details
corresponding to the "short" letters shown in the test progress::
@@ -35,15 +35,16 @@
when run on a Python3.3 interpreter::
import sys
- @pytest.mark.skipif(sys.version_info >= (3,3),
+ @pytest.mark.skipif(sys.version_info >= (3,3),
reason="requires python3.3")
def test_function():
...
During test function setup the condition ("sys.version_info >= (3,3)") is
checked. If it evaluates to True, the test function will be skipped
-with the specified reason. Note that pytest enforces specifying a reason
+with the specified reason. Note that pytest enforces specifying a reason
in order to report meaningful "skip reasons" (e.g. when using ``-rs``).
+If the condition is a string, it will be evaluated as python expression.
You can share skipif markers between modules. Consider this test module::
@@ -69,7 +70,7 @@
where you define the markers which you then consistently apply
throughout your test suite.
-Alternatively, the pre pytest-2.4 way to specify `condition strings `_ instead of booleans will remain fully supported in future
+Alternatively, the pre pytest-2.4 way to specify `condition strings `_ instead of booleans will remain fully supported in future
versions of pytest. It couldn't be easily used for importing markers
between test modules so it's no longer advertised as the primary method.
@@ -78,10 +79,10 @@
---------------------------------------------
As with all function :ref:`marking ` you can skip test functions at the
-`whole class- or module level`_. If your code targets python2.6 or above you
+`whole class- or module level`_. If your code targets python2.6 or above you
use the skipif decorator (and any other marker) on classes::
- @pytest.mark.skipif(sys.platform == 'win32',
+ @pytest.mark.skipif(sys.platform == 'win32',
reason="requires windows")
class TestPosixCalls:
@@ -102,7 +103,7 @@
"will not be setup or run under 'win32' platform"
As with the class-decorator, the ``pytestmark`` special name tells
-py.test to apply it to each test function in the class.
+py.test to apply it to each test function in the class.
If you want to skip all test functions of a module, you must use
the ``pytestmark`` name on the global level::
@@ -142,7 +143,7 @@
As with skipif_ you can also mark your expectation of a failure
on a particular platform::
- @pytest.mark.xfail(sys.version_info >= (3,3),
+ @pytest.mark.xfail(sys.version_info >= (3,3),
reason="python3.3 api changes")
def test_function():
...
@@ -159,12 +160,12 @@
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 6 items
-
+
xfail_demo.py xxxxxx
========================= short test summary info ==========================
XFAIL xfail_demo.py::test_hello
XFAIL xfail_demo.py::test_hello2
- reason: [NOTRUN]
+ reason: [NOTRUN]
XFAIL xfail_demo.py::test_hello3
condition: hasattr(os, 'sep')
XFAIL xfail_demo.py::test_hello4
@@ -173,7 +174,7 @@
condition: pytest.__version__[0] != "17"
XFAIL xfail_demo.py::test_hello6
reason: reason
-
+
======================== 6 xfailed in 0.05 seconds =========================
.. _`skip/xfail with parametrize`:
@@ -202,7 +203,7 @@
Imperative xfail from within a test or setup function
------------------------------------------------------
-If you cannot declare xfail- of skipif conditions at import
+If you cannot declare xfail- of skipif conditions at import
time you can also imperatively produce an according outcome
imperatively, in test or setup code::
@@ -227,7 +228,7 @@
docutils = pytest.importorskip("docutils", minversion="0.3")
-The version will be read from the specified
+The version will be read from the specified
module's ``__version__`` attribute.
@@ -244,18 +245,18 @@
def test_function():
...
-During test function setup the skipif condition is evaluated by calling
-``eval('sys.version_info >= (3,0)', namespace)``. The namespace contains
+During test function setup the skipif condition is evaluated by calling
+``eval('sys.version_info >= (3,0)', namespace)``. The namespace contains
all the module globals, and ``os`` and ``sys`` as a minimum.
-Since pytest-2.4 `condition booleans`_ are considered preferable
+Since pytest-2.4 `condition booleans`_ are considered preferable
because markers can then be freely imported between test modules.
With strings you need to import not only the marker but all variables
everything used by the marker, which violates encapsulation.
The reason for specifying the condition as a string was that py.test can
-report a summary of skip conditions based purely on the condition string.
-With conditions as booleans you are required to specify a ``reason`` string.
+report a summary of skip conditions based purely on the condition string.
+With conditions as booleans you are required to specify a ``reason`` string.
Note that string conditions will remain fully supported and you are free
to use them if you have no need for cross-importing markers.
@@ -266,7 +267,7 @@
* the namespace is initialized by putting the ``sys`` and ``os`` modules
and the pytest ``config`` object into it.
-
+
* updated with the module globals of the test function for which the
expression is applied.
diff -r 16e79a864e9661f52ef93a2a4afbeae3299664e7 -r af665883e9f2f79a4c4c06580f4aeaf2cb5bfdda testing/test_skipping.py
--- a/testing/test_skipping.py
+++ b/testing/test_skipping.py
@@ -100,6 +100,18 @@
expl = ev.getexplanation()
assert expl == "condition: not hasattr(os, 'murks')"
+ def test_marked_skip_with_not_string(self, testdir):
+ item = testdir.getitem("""
+ import pytest
+ @pytest.mark.skipif(False)
+ def test_func():
+ pass
+ """)
+ ev = MarkEvaluator(item, 'skipif')
+ with pytest.raises(pytest.fail.Exception) as exc:
+ assert ev.istrue()
+ assert """Failed: you need to specify reason=STRING when using booleans as conditions.""" in exc.value.msg
+
def test_skipif_class(self, testdir):
item, = testdir.getitems("""
import pytest
https://bitbucket.org/hpk42/pytest/commits/f20b8a999d37/
Changeset: f20b8a999d37
User: hpk42
Date: 2013-07-06 20:13:27
Summary: Merged in bubenkoff/pytest/329-skipif-requires-expression-as-a-string (pull request #43)
re #329 add test for skipif failure when you pass boolean without the reason. add emphasize to the docs.
Affected #: 2 files
diff -r cc8871c02a5e4e34ad8e42121ffefb0651304b67 -r f20b8a999d37a9f5b18d914c011a065ecbd543ee doc/en/skipping.txt
--- a/doc/en/skipping.txt
+++ b/doc/en/skipping.txt
@@ -10,11 +10,11 @@
may call helper functions during execution of setup or test functions.
A *skip* means that you expect your test to pass unless the environment
-(e.g. wrong Python interpreter, missing dependency) prevents it to run.
+(e.g. wrong Python interpreter, missing dependency) prevents it to run.
And *xfail* means that your test can run but you expect it to fail
because there is an implementation problem.
-py.test counts and lists *skip* and *xfail* tests separately. Detailed
+py.test counts and lists *skip* and *xfail* tests separately. Detailed
information about skipped/xfailed tests is not shown by default to avoid
cluttering the output. You can use the ``-r`` option to see details
corresponding to the "short" letters shown in the test progress::
@@ -35,15 +35,16 @@
when run on a Python3.3 interpreter::
import sys
- @pytest.mark.skipif(sys.version_info >= (3,3),
+ @pytest.mark.skipif(sys.version_info >= (3,3),
reason="requires python3.3")
def test_function():
...
During test function setup the condition ("sys.version_info >= (3,3)") is
checked. If it evaluates to True, the test function will be skipped
-with the specified reason. Note that pytest enforces specifying a reason
+with the specified reason. Note that pytest enforces specifying a reason
in order to report meaningful "skip reasons" (e.g. when using ``-rs``).
+If the condition is a string, it will be evaluated as python expression.
You can share skipif markers between modules. Consider this test module::
@@ -69,7 +70,7 @@
where you define the markers which you then consistently apply
throughout your test suite.
-Alternatively, the pre pytest-2.4 way to specify `condition strings `_ instead of booleans will remain fully supported in future
+Alternatively, the pre pytest-2.4 way to specify `condition strings `_ instead of booleans will remain fully supported in future
versions of pytest. It couldn't be easily used for importing markers
between test modules so it's no longer advertised as the primary method.
@@ -78,10 +79,10 @@
---------------------------------------------
As with all function :ref:`marking ` you can skip test functions at the
-`whole class- or module level`_. If your code targets python2.6 or above you
+`whole class- or module level`_. If your code targets python2.6 or above you
use the skipif decorator (and any other marker) on classes::
- @pytest.mark.skipif(sys.platform == 'win32',
+ @pytest.mark.skipif(sys.platform == 'win32',
reason="requires windows")
class TestPosixCalls:
@@ -102,7 +103,7 @@
"will not be setup or run under 'win32' platform"
As with the class-decorator, the ``pytestmark`` special name tells
-py.test to apply it to each test function in the class.
+py.test to apply it to each test function in the class.
If you want to skip all test functions of a module, you must use
the ``pytestmark`` name on the global level::
@@ -142,7 +143,7 @@
As with skipif_ you can also mark your expectation of a failure
on a particular platform::
- @pytest.mark.xfail(sys.version_info >= (3,3),
+ @pytest.mark.xfail(sys.version_info >= (3,3),
reason="python3.3 api changes")
def test_function():
...
@@ -159,12 +160,12 @@
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.5
collected 6 items
-
+
xfail_demo.py xxxxxx
========================= short test summary info ==========================
XFAIL xfail_demo.py::test_hello
XFAIL xfail_demo.py::test_hello2
- reason: [NOTRUN]
+ reason: [NOTRUN]
XFAIL xfail_demo.py::test_hello3
condition: hasattr(os, 'sep')
XFAIL xfail_demo.py::test_hello4
@@ -173,7 +174,7 @@
condition: pytest.__version__[0] != "17"
XFAIL xfail_demo.py::test_hello6
reason: reason
-
+
======================== 6 xfailed in 0.05 seconds =========================
.. _`skip/xfail with parametrize`:
@@ -202,7 +203,7 @@
Imperative xfail from within a test or setup function
------------------------------------------------------
-If you cannot declare xfail- of skipif conditions at import
+If you cannot declare xfail- of skipif conditions at import
time you can also imperatively produce an according outcome
imperatively, in test or setup code::
@@ -227,7 +228,7 @@
docutils = pytest.importorskip("docutils", minversion="0.3")
-The version will be read from the specified
+The version will be read from the specified
module's ``__version__`` attribute.
@@ -244,18 +245,18 @@
def test_function():
...
-During test function setup the skipif condition is evaluated by calling
-``eval('sys.version_info >= (3,0)', namespace)``. The namespace contains
+During test function setup the skipif condition is evaluated by calling
+``eval('sys.version_info >= (3,0)', namespace)``. The namespace contains
all the module globals, and ``os`` and ``sys`` as a minimum.
-Since pytest-2.4 `condition booleans`_ are considered preferable
+Since pytest-2.4 `condition booleans`_ are considered preferable
because markers can then be freely imported between test modules.
With strings you need to import not only the marker but all variables
everything used by the marker, which violates encapsulation.
The reason for specifying the condition as a string was that py.test can
-report a summary of skip conditions based purely on the condition string.
-With conditions as booleans you are required to specify a ``reason`` string.
+report a summary of skip conditions based purely on the condition string.
+With conditions as booleans you are required to specify a ``reason`` string.
Note that string conditions will remain fully supported and you are free
to use them if you have no need for cross-importing markers.
@@ -266,7 +267,7 @@
* the namespace is initialized by putting the ``sys`` and ``os`` modules
and the pytest ``config`` object into it.
-
+
* updated with the module globals of the test function for which the
expression is applied.
diff -r cc8871c02a5e4e34ad8e42121ffefb0651304b67 -r f20b8a999d37a9f5b18d914c011a065ecbd543ee testing/test_skipping.py
--- a/testing/test_skipping.py
+++ b/testing/test_skipping.py
@@ -100,6 +100,18 @@
expl = ev.getexplanation()
assert expl == "condition: not hasattr(os, 'murks')"
+ def test_marked_skip_with_not_string(self, testdir):
+ item = testdir.getitem("""
+ import pytest
+ @pytest.mark.skipif(False)
+ def test_func():
+ pass
+ """)
+ ev = MarkEvaluator(item, 'skipif')
+ with pytest.raises(pytest.fail.Exception) as exc:
+ assert ev.istrue()
+ assert """Failed: you need to specify reason=STRING when using booleans as conditions.""" in exc.value.msg
+
def test_skipif_class(self, testdir):
item, = testdir.getitems("""
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 Mon Jul 8 15:39:19 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Mon, 08 Jul 2013 13:39:19 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: fix docs wrt norecursedirs,
thanks @mgax
Message-ID: <20130708133919.2874.79827@app18.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/bcf6f8c25f89/
Changeset: bcf6f8c25f89
User: hpk42
Date: 2013-07-08 15:39:14
Summary: fix docs wrt norecursedirs, thanks @mgax
Affected #: 1 file
diff -r f20b8a999d37a9f5b18d914c011a065ecbd543ee -r bcf6f8c25f89879da9dc994fec8320ad5d1912cc doc/en/customize.txt
--- a/doc/en/customize.txt
+++ b/doc/en/customize.txt
@@ -97,7 +97,7 @@
[seq] matches any character in seq
[!seq] matches any char not in seq
- Default patterns are ``.* _* CVS {args}``. Setting a ``norecursedir``
+ Default patterns are ``.* _darcs CVS {args}``. Setting a ``norecursedir``
replaces the default. Here is an example of how to avoid
certain directories::
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 Jul 8 15:55:41 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Mon, 08 Jul 2013 13:55:41 -0000
Subject: [Pytest-commit] commit/pytest: 3 new changesets
Message-ID: <20130708135541.1663.71900@app01.ash-private.bitbucket.org>
3 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/1c51eba0e480/
Changeset: 1c51eba0e480
Branch: 320-class-scoped-fixture-caching-is-broken-if
User: bubenkoff
Date: 2013-07-06 21:30:24
Summary: re #320 fallback to test scope if the class-scoped fixture is used in non-class-based test function
Affected #: 3 files
diff -r cc8871c02a5e4e34ad8e42121ffefb0651304b67 -r 1c51eba0e48065351d33a0087710dae4d49b768d _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -1317,7 +1317,8 @@
x = self._pyfuncitem.getparent(pytest.Class)
if x is not None:
return x
- scope = "module"
+ # fallback to function
+ return self._pyfuncitem
if scope == "module":
return self._pyfuncitem.getparent(pytest.Module)
raise ValueError("unknown finalization scope %r" %(scope,))
diff -r cc8871c02a5e4e34ad8e42121ffefb0651304b67 -r 1c51eba0e48065351d33a0087710dae4d49b768d testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -513,12 +513,12 @@
def test_request_cachedsetup_class(self, testdir):
reprec = testdir.inline_runsource("""
- mysetup = ["hello", "hello2"].pop
+ mysetup = ["hello", "hello2", "hello3"].pop
def pytest_funcarg__something(request):
return request.cached_setup(mysetup, scope="class")
def test_func1(something):
- assert something == "hello2"
+ assert something == "hello3"
def test_func2(something):
assert something == "hello2"
class TestClass:
@@ -1090,7 +1090,7 @@
def arg():
l.append(1)
return 0
- @pytest.fixture(scope="class", autouse=True)
+ @pytest.fixture(scope="module", autouse=True)
def something(arg):
l.append(2)
diff -r cc8871c02a5e4e34ad8e42121ffefb0651304b67 -r 1c51eba0e48065351d33a0087710dae4d49b768d testing/test_fixture_scope.py
--- /dev/null
+++ b/testing/test_fixture_scope.py
@@ -0,0 +1,28 @@
+"""Tests for fixtures with different scoping."""
+
+
+def test_class_scope_with_normal_tests(testdir):
+ testpath = testdir.makepyfile("""
+ import pytest
+
+ class Box:
+ value = 0
+
+ @pytest.fixture(scope='class')
+ def a(request):
+ Box.value += 1
+ return Box.value
+
+ def test_a(a):
+ assert a == 1
+
+ class Test1:
+ def test_b(self, a):
+ assert a == 2
+
+ class Test2:
+ def test_c(self, a):
+ assert a == 3""")
+ reprec = testdir.inline_run(testpath)
+ for test in ['test_a', 'test_b', 'test_c']:
+ assert reprec.matchreport(test).passed
https://bitbucket.org/hpk42/pytest/commits/635c9c36e481/
Changeset: 635c9c36e481
Branch: 320-class-scoped-fixture-caching-is-broken-if
User: hpk42
Date: 2013-07-08 15:45:07
Summary: Close branch 320-class-scoped-fixture-caching-is-broken-if
Affected #: 0 files
https://bitbucket.org/hpk42/pytest/commits/602a8ebee9ba/
Changeset: 602a8ebee9ba
User: hpk42
Date: 2013-07-08 15:54:38
Summary: fix issue320 - fix class scope for fixtures when mixed with
module-level functions. Thanks Anatloy Bubenkoff.
Affected #: 5 files
diff -r bcf6f8c25f89879da9dc994fec8320ad5d1912cc -r 602a8ebee9ba44b91699ad86426711f0aba35f7b AUTHORS
--- a/AUTHORS
+++ b/AUTHORS
@@ -9,6 +9,7 @@
Jason R. Coombs
Wouter van Ackooy
Samuele Pedroni
+Anatoly Bubenkoff
Brianna Laugher
Carl Friedrich Bolz
Armin Rigo
diff -r bcf6f8c25f89879da9dc994fec8320ad5d1912cc -r 602a8ebee9ba44b91699ad86426711f0aba35f7b CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
Changes between 2.3.5 and 2.4.DEV
-----------------------------------
+- fix issue320 - fix class scope for fixtures when mixed with
+ module-level functions. Thanks Anatloy Bubenkoff.
+
- you can specify "-q" or "-qq" to get different levels of "quieter"
reporting (thanks Katarzyna Jachim)
diff -r bcf6f8c25f89879da9dc994fec8320ad5d1912cc -r 602a8ebee9ba44b91699ad86426711f0aba35f7b _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -1317,7 +1317,8 @@
x = self._pyfuncitem.getparent(pytest.Class)
if x is not None:
return x
- scope = "module"
+ # fallback to function
+ return self._pyfuncitem
if scope == "module":
return self._pyfuncitem.getparent(pytest.Module)
raise ValueError("unknown finalization scope %r" %(scope,))
diff -r bcf6f8c25f89879da9dc994fec8320ad5d1912cc -r 602a8ebee9ba44b91699ad86426711f0aba35f7b testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -513,12 +513,12 @@
def test_request_cachedsetup_class(self, testdir):
reprec = testdir.inline_runsource("""
- mysetup = ["hello", "hello2"].pop
+ mysetup = ["hello", "hello2", "hello3"].pop
def pytest_funcarg__something(request):
return request.cached_setup(mysetup, scope="class")
def test_func1(something):
- assert something == "hello2"
+ assert something == "hello3"
def test_func2(something):
assert something == "hello2"
class TestClass:
@@ -1090,7 +1090,7 @@
def arg():
l.append(1)
return 0
- @pytest.fixture(scope="class", autouse=True)
+ @pytest.fixture(scope="module", autouse=True)
def something(arg):
l.append(2)
diff -r bcf6f8c25f89879da9dc994fec8320ad5d1912cc -r 602a8ebee9ba44b91699ad86426711f0aba35f7b testing/test_fixture_scope.py
--- /dev/null
+++ b/testing/test_fixture_scope.py
@@ -0,0 +1,28 @@
+"""Tests for fixtures with different scoping."""
+
+
+def test_class_scope_with_normal_tests(testdir):
+ testpath = testdir.makepyfile("""
+ import pytest
+
+ class Box:
+ value = 0
+
+ @pytest.fixture(scope='class')
+ def a(request):
+ Box.value += 1
+ return Box.value
+
+ def test_a(a):
+ assert a == 1
+
+ class Test1:
+ def test_b(self, a):
+ assert a == 2
+
+ class Test2:
+ def test_c(self, a):
+ assert a == 3""")
+ reprec = testdir.inline_run(testpath)
+ for test in ['test_a', 'test_b', 'test_c']:
+ assert reprec.matchreport(test).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 Mon Jul 8 16:27:57 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Mon, 08 Jul 2013 14:27:57 -0000
Subject: [Pytest-commit] commit/tox: magopian: fixes #87 : unset
VIRTUALENV_PYTHON before calling virtualenv
Message-ID: <20130708142757.30313.42936@app07.ash-private.bitbucket.org>
1 new commit in tox:
https://bitbucket.org/hpk42/tox/commits/7be299d36432/
Changeset: 7be299d36432
User: magopian
Date: 2013-07-06 18:16:30
Summary: fixes #87 : unset VIRTUALENV_PYTHON before calling virtualenv
Affected #: 2 files
diff -r d315272501bafb1a799fad80b2555002f9bd524d -r 7be299d36432aab33fd7f7ffc0ee5dfd5df6dbf8 tests/test_z_cmdline.py
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -382,6 +382,15 @@
"*create*",
])
+def test_env_VIRTUALENV_PYTHON(initproj, cmd, monkeypatch):
+ initproj("example123", filedefs={'tox.ini': ''})
+ monkeypatch.setenv("VIRTUALENV_PYTHON", '/FOO')
+ result = cmd.run("tox", "-v", "--notest")
+ assert not result.ret, result.stdout.lines
+ result.stdout.fnmatch_lines([
+ "*create*",
+ ])
+
def test_sdistonly(initproj, cmd):
initproj("example123", filedefs={'tox.ini': """
"""})
diff -r d315272501bafb1a799fad80b2555002f9bd524d -r 7be299d36432aab33fd7f7ffc0ee5dfd5df6dbf8 tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -301,6 +301,10 @@
def _pcall(self, args, venv=True, cwd=None, extraenv={},
action=None, redirect=True):
+ try:
+ del os.environ['VIRTUALENV_PYTHON']
+ except KeyError:
+ pass
assert cwd
cwd.ensure(dir=1)
old = self.patchPATH()
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 Tue Jul 9 13:40:10 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Tue, 09 Jul 2013 11:40:10 -0000
Subject: [Pytest-commit] commit/tox: hpk42: always unset PYTHONDONTWRITEBYTE
because newer setuptools doesn't like it
Message-ID: <20130709114010.25083.68003@app17.ash-private.bitbucket.org>
1 new commit in tox:
https://bitbucket.org/hpk42/tox/commits/63d37ba9cc8b/
Changeset: 63d37ba9cc8b
User: hpk42
Date: 2013-07-09 13:40:04
Summary: always unset PYTHONDONTWRITEBYTE because newer setuptools doesn't like it
Affected #: 6 files
diff -r 7be299d36432aab33fd7f7ffc0ee5dfd5df6dbf8 -r 63d37ba9cc8babe926e45f9e8294841148b0451b CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+1.5.1.dev
+-----------------
+
+- always unset PYTHONDONTWRITEBYTE because newer setuptools doesn't like it
+
1.5.0
-----------------
diff -r 7be299d36432aab33fd7f7ffc0ee5dfd5df6dbf8 -r 63d37ba9cc8babe926e45f9e8294841148b0451b doc/index.txt
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -1,7 +1,8 @@
Welcome to the tox automation project
===============================================
-.. note:: Upcoming: `professional testing with pytest and tox `_ , 24th-26th June 2013, Leipzig.
+..
+ Upcoming: `professional testing with pytest and tox `_ , 24th-26th June 2013, Leipzig.
vision: standardize testing in Python
---------------------------------------------
diff -r 7be299d36432aab33fd7f7ffc0ee5dfd5df6dbf8 -r 63d37ba9cc8babe926e45f9e8294841148b0451b setup.py
--- a/setup.py
+++ b/setup.py
@@ -26,7 +26,7 @@
description='virtualenv-based automation of test activities',
long_description=open("README.rst").read(),
url='http://tox.testrun.org/',
- version='1.5.0',
+ version='1.5.1.dev1',
license='http://opensource.org/licenses/MIT',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
author='holger krekel',
diff -r 7be299d36432aab33fd7f7ffc0ee5dfd5df6dbf8 -r 63d37ba9cc8babe926e45f9e8294841148b0451b tox/__init__.py
--- a/tox/__init__.py
+++ b/tox/__init__.py
@@ -1,5 +1,5 @@
#
-__version__ = '1.5.0'
+__version__ = '1.5.1.dev1'
class exception:
class Error(Exception):
diff -r 7be299d36432aab33fd7f7ffc0ee5dfd5df6dbf8 -r 63d37ba9cc8babe926e45f9e8294841148b0451b tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -301,10 +301,11 @@
def _pcall(self, args, venv=True, cwd=None, extraenv={},
action=None, redirect=True):
- try:
- del os.environ['VIRTUALENV_PYTHON']
- except KeyError:
- pass
+ for name in ("VIRTUALENV_PYTHON", "PYTHONDONTWRITEBYTECODE"):
+ try:
+ del os.environ[name]
+ except KeyError:
+ pass
assert cwd
cwd.ensure(dir=1)
old = self.patchPATH()
diff -r 7be299d36432aab33fd7f7ffc0ee5dfd5df6dbf8 -r 63d37ba9cc8babe926e45f9e8294841148b0451b toxbootstrap.py
--- a/toxbootstrap.py
+++ b/toxbootstrap.py
@@ -58,7 +58,7 @@
"""
-__version__ = '1.5.0'
+__version__ = '1.5.1.dev1'
import sys
import os
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 Jul 10 14:30:15 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 10 Jul 2013 12:30:15 -0000
Subject: [Pytest-commit] commit/pytest: bubenkoff: Update README.rst
Message-ID: <20130710123015.460.56648@app15.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/9d9f4a158f2f/
Changeset: 9d9f4a158f2f
User: bubenkoff
Date: 2013-07-10 13:51:43
Summary: Update README.rst
change the travis link and image to be correct
Affected #: 1 file
diff -r 602a8ebee9ba44b91699ad86426711f0aba35f7b -r 9d9f4a158f2f1b8e4094584701eb6e45168d0d7c README.rst
--- a/README.rst
+++ b/README.rst
@@ -1,4 +1,3 @@
-
The ``py.test`` testing tool makes it easy to write small tests, yet
scales to support complex functional testing. It provides
@@ -16,8 +15,8 @@
- many `external plugins `_.
-.. image:: https://secure.travis-ci.org/bubenkoff/pytest.png?branch=travis-integration
- :target: http://travis-ci.org/bubenkoff/pytest
+.. image:: https://secure.travis-ci.org/hpk42/pytest.png?branch=travis-integration
+ :target: http://travis-ci.org/hpk42/pytest
A simple example for a 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 Thu Jul 11 10:51:17 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Thu, 11 Jul 2013 08:51:17 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: change copyright years
Message-ID: <20130711085117.637.82129@app08.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/590415123958/
Changeset: 590415123958
User: hpk42
Date: 2013-07-11 10:50:59
Summary: change copyright years
Affected #: 1 file
diff -r 9d9f4a158f2f1b8e4094584701eb6e45168d0d7c -r 5904151239588a7c187932b044c4e480f6965504 README.rst
--- a/README.rst
+++ b/README.rst
@@ -35,4 +35,4 @@
http://bitbucket.org/hpk42/pytest/issues/
-Copyright Holger Krekel and others, 2004-2012
+Copyright Holger Krekel and others, 2004-2013
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 Jul 11 11:13:16 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Thu, 11 Jul 2013 09:13:16 -0000
Subject: [Pytest-commit] commit/tox: 10 new changesets
Message-ID: <20130711091316.21551.77833@app02.ash-private.bitbucket.org>
10 new commits in tox:
https://bitbucket.org/hpk42/tox/commits/cd64bee5b235/
Changeset: cd64bee5b235
User: lukaszb
Date: 2013-06-14 18:24:17
Summary: Created initial documentation for development environments -- related with #101
Affected #: 2 files
diff -r 1c746939df7f57bae11fe81010446d5c8dc3dae6 -r cd64bee5b235661b8b2dc13294a6cc55603a6812 doc/example/devenv.txt
--- /dev/null
+++ b/doc/example/devenv.txt
@@ -0,0 +1,64 @@
+
+Development environment
+=======================
+
+Tox can be used to prepare development virtual environment for local projects.
+This feature can be useful in order to preserve environment across team members
+working on same project. It can be also used by deployment tools to prepare
+proper environments.
+
+*devenv* would be created at specific directory, not within ``.tox`` directory
+as other test environments. Other than that, configuration for this environment
+is very similar to other tox envs.
+
+
+Configuration
+-------------
+
+Firstly, you need to prepare configuration for your development environment. In
+order to do that, we must define proper section at ``tox.ini`` file and tell at
+what directory environment should be created. Moreover, we need to specify
+python version that should be picked::
+
+ [devenv]
+ envdir = devenv
+ basepython = python2.7
+
+
+Actually, you can configure a lot more, those are the only required settings.
+In example you can add ``deps`` and ``commands`` settings.
+
+
+.. note:: ``envdir`` should be *relative* path to where ``tox.ini`` is located.
+
+
+Creating development environment
+--------------------------------
+
+Once ``devenv`` section is defined we can instrument tox to create our
+environment::
+
+ tox --devenv
+
+This will create an environment at path specified by ``envdir`` under ``devenv``
+section.
+
+
+
+Full configuration example
+--------------------------
+
+Let's say we want our development environment sit at ``devenv``. We create this
+directory manually and put ``requirements.txt`` file there. We want to work on
+Python 2.7.
+
+Here is example configuration for that::
+
+ [devenv]
+ envdir = devenv
+ changedir = devenv
+ basepython = python2.7
+ commands =
+ pip install -r requirements.txt
+
+
diff -r 1c746939df7f57bae11fe81010446d5c8dc3dae6 -r cd64bee5b235661b8b2dc13294a6cc55603a6812 doc/examples.txt
--- a/doc/examples.txt
+++ b/doc/examples.txt
@@ -11,4 +11,5 @@
example/nose.txt
example/general.txt
example/jenkins.txt
+ example/devenv.txt
https://bitbucket.org/hpk42/tox/commits/8b6f18ce8d64/
Changeset: 8b6f18ce8d64
User: lukaszb
Date: 2013-06-20 20:31:16
Summary: Updated documentation for development environment
Affected #: 2 files
diff -r cd64bee5b235661b8b2dc13294a6cc55603a6812 -r 8b6f18ce8d64eff4e9b3776a7553e8231d7a6ec1 doc/config.txt
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -163,6 +163,14 @@
(including when installing the project sdist package).
+.. confval:: envdir
+
+ .. versionadded:: 1.5
+
+ User can set specific path for environment. If path would not be absolute it
+ would be treated as relative to ``{toxinidir}``. **default**:
+ ``{toxworkdir}/{envname}``
+
Substitutions
---------------------
diff -r cd64bee5b235661b8b2dc13294a6cc55603a6812 -r 8b6f18ce8d64eff4e9b3776a7553e8231d7a6ec1 doc/example/devenv.txt
--- a/doc/example/devenv.txt
+++ b/doc/example/devenv.txt
@@ -20,7 +20,7 @@
what directory environment should be created. Moreover, we need to specify
python version that should be picked::
- [devenv]
+ [testenv:devenv]
envdir = devenv
basepython = python2.7
@@ -38,10 +38,10 @@
Once ``devenv`` section is defined we can instrument tox to create our
environment::
- tox --devenv
+ tox -e devenv --envonly
-This will create an environment at path specified by ``envdir`` under ``devenv``
-section.
+This will create an environment at path specified by ``envdir`` under
+``[testenv:devenv]`` section.
@@ -54,7 +54,7 @@
Here is example configuration for that::
- [devenv]
+ [testenv:devenv]
envdir = devenv
changedir = devenv
basepython = python2.7
https://bitbucket.org/hpk42/tox/commits/9c8a6ba3a8c0/
Changeset: 9c8a6ba3a8c0
User: lukaszb
Date: 2013-06-20 21:05:30
Summary: Added tests for envdir config
Affected #: 1 file
diff -r 8b6f18ce8d64eff4e9b3776a7553e8231d7a6ec1 -r 9c8a6ba3a8c0913d582da4ed9b1913e8d0664fde tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -44,6 +44,22 @@
assert dep2.indexserver.name == "xyz"
assert dep2.indexserver.url == "xyz_repo"
+ def test_envdir_set_manually(self, tmpdir, newconfig):
+ config = newconfig([], """
+ [testenv:devenv]
+ envdir = devenv
+ """)
+ envconfig = config.envconfigs['devenv']
+ assert envconfig.envdir == tmpdir.join('devenv')
+
+ def test_envdir_set_manually_with_substitutions(self, tmpdir, newconfig):
+ config = newconfig([], """
+ [testenv:devenv]
+ envdir = {toxworkdir}/foobar
+ """)
+ envconfig = config.envconfigs['devenv']
+ assert envconfig.envdir == config.toxworkdir.join('foobar')
+
class TestConfigPackage:
def test_defaults(self, tmpdir, newconfig):
config = newconfig([], "")
https://bitbucket.org/hpk42/tox/commits/20ef6ad9ee7d/
Changeset: 20ef6ad9ee7d
User: lukaszb
Date: 2013-06-20 22:06:49
Summary: Dropped note from devenv - envdir is now better documented at config.txt
Affected #: 1 file
diff -r 9c8a6ba3a8c0913d582da4ed9b1913e8d0664fde -r 20ef6ad9ee7d952a603c7449b3478ad6b00f28b2 doc/example/devenv.txt
--- a/doc/example/devenv.txt
+++ b/doc/example/devenv.txt
@@ -29,8 +29,6 @@
In example you can add ``deps`` and ``commands`` settings.
-.. note:: ``envdir`` should be *relative* path to where ``tox.ini`` is located.
-
Creating development environment
--------------------------------
https://bitbucket.org/hpk42/tox/commits/64a59fad08de/
Changeset: 64a59fad08de
User: lukaszb
Date: 2013-06-20 22:13:01
Summary: Removed --envonly switch from devenv docs
Affected #: 1 file
diff -r 20ef6ad9ee7d952a603c7449b3478ad6b00f28b2 -r 64a59fad08de78bdc58fa941eba29b37eeb8f9f8 doc/example/devenv.txt
--- a/doc/example/devenv.txt
+++ b/doc/example/devenv.txt
@@ -36,7 +36,7 @@
Once ``devenv`` section is defined we can instrument tox to create our
environment::
- tox -e devenv --envonly
+ tox -e devenv
This will create an environment at path specified by ``envdir`` under
``[testenv:devenv]`` section.
https://bitbucket.org/hpk42/tox/commits/a8b1cc2184d5/
Changeset: a8b1cc2184d5
User: lukaszb
Date: 2013-06-20 23:20:02
Summary: Documented 'package' config for test envs
Affected #: 2 files
diff -r 64a59fad08de78bdc58fa941eba29b37eeb8f9f8 -r a8b1cc2184d5241ce0df85e06c4d7a07637f2e91 doc/config.txt
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -171,6 +171,16 @@
would be treated as relative to ``{toxinidir}``. **default**:
``{toxworkdir}/{envname}``
+
+.. confval:: package=BOOL
+
+ .. versionadded:: 1.5
+
+ Set to ``False`` if you don't want tox to perform package-related steps
+ (building source distribution and installing it). Might be useful for
+ non-package projects (i.e. all that lacks ``setup.py`` file). **default**:
+ ``True``.
+
Substitutions
---------------------
diff -r 64a59fad08de78bdc58fa941eba29b37eeb8f9f8 -r a8b1cc2184d5241ce0df85e06c4d7a07637f2e91 doc/example/devenv.txt
--- a/doc/example/devenv.txt
+++ b/doc/example/devenv.txt
@@ -18,11 +18,13 @@
Firstly, you need to prepare configuration for your development environment. In
order to do that, we must define proper section at ``tox.ini`` file and tell at
what directory environment should be created. Moreover, we need to specify
-python version that should be picked::
+python version that should be picked and tell tox not to perform any package
+related steps::
[testenv:devenv]
envdir = devenv
basepython = python2.7
+ package = False
Actually, you can configure a lot more, those are the only required settings.
@@ -53,6 +55,7 @@
Here is example configuration for that::
[testenv:devenv]
+ package = False
envdir = devenv
changedir = devenv
basepython = python2.7
https://bitbucket.org/hpk42/tox/commits/0eacb212fed4/
Changeset: 0eacb212fed4
User: lukaszb
Date: 2013-06-20 23:42:02
Summary: Added package flag to venv config
Affected #: 2 files
diff -r a8b1cc2184d5241ce0df85e06c4d7a07637f2e91 -r 0eacb212fed4a9fce77fd6ffc2cf2dd619387835 tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -60,6 +60,20 @@
envconfig = config.envconfigs['devenv']
assert envconfig.envdir == config.toxworkdir.join('foobar')
+ def test_package_flag(self, tmpdir, newconfig):
+ config = newconfig([], """
+ [testenv:py27]
+ """)
+ envconfig = config.envconfigs['py27']
+ assert envconfig.package == True
+
+ config = newconfig([], """
+ [testenv:py27]
+ package = False
+ """)
+ envconfig = config.envconfigs['py27']
+ assert envconfig.package == False
+
class TestConfigPackage:
def test_defaults(self, tmpdir, newconfig):
config = newconfig([], "")
diff -r a8b1cc2184d5241ce0df85e06c4d7a07637f2e91 -r 0eacb212fed4a9fce77fd6ffc2cf2dd619387835 tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -256,6 +256,7 @@
reader = IniReader(self._cfg, fallbacksections=["testenv"])
reader.addsubstitions(**subs)
vc.envdir = reader.getpath(section, "envdir", "{toxworkdir}/%s" % name)
+ vc.package = reader.getbool(section, "package", True)
vc.args_are_paths = reader.getbool(section, "args_are_paths", True)
if reader.getdefault(section, "python", None):
raise tox.exception.ConfigError(
https://bitbucket.org/hpk42/tox/commits/eacb5ca142ab/
Changeset: eacb5ca142ab
User: lukaszb
Date: 2013-07-10 23:21:14
Summary: Simplified devenv example docs to use only existing interfaces.
Affected #: 1 file
diff -r 0eacb212fed4a9fce77fd6ffc2cf2dd619387835 -r eacb5ca142abf0b855d9ed2f8d61857b43ced268 doc/example/devenv.txt
--- a/doc/example/devenv.txt
+++ b/doc/example/devenv.txt
@@ -7,10 +7,6 @@
working on same project. It can be also used by deployment tools to prepare
proper environments.
-*devenv* would be created at specific directory, not within ``.tox`` directory
-as other test environments. Other than that, configuration for this environment
-is very similar to other tox envs.
-
Configuration
-------------
@@ -18,18 +14,18 @@
Firstly, you need to prepare configuration for your development environment. In
order to do that, we must define proper section at ``tox.ini`` file and tell at
what directory environment should be created. Moreover, we need to specify
-python version that should be picked and tell tox not to perform any package
-related steps::
+python version that should be picked::
[testenv:devenv]
envdir = devenv
basepython = python2.7
- package = False
+ commands =
+ deps =
Actually, you can configure a lot more, those are the only required settings.
-In example you can add ``deps`` and ``commands`` settings.
-
+In example you can add ``deps`` and ``commands`` settings. Here, we tell tox
+not to pick ``commands`` or ``deps`` from base ``testenv`` configuration.
Creating development environment
@@ -44,22 +40,18 @@
``[testenv:devenv]`` section.
-
Full configuration example
--------------------------
-Let's say we want our development environment sit at ``devenv``. We create this
-directory manually and put ``requirements.txt`` file there. We want to work on
-Python 2.7.
+Let's say we want our development environment sit at ``devenv`` and pull
+packages from ``requirements.txt`` file which we create at the same directory
+as ``tox.ini`` file. We also want to speciy Python version to be 2.7.
Here is example configuration for that::
[testenv:devenv]
- package = False
envdir = devenv
- changedir = devenv
basepython = python2.7
commands =
pip install -r requirements.txt
-
https://bitbucket.org/hpk42/tox/commits/ecb095208e42/
Changeset: ecb095208e42
User: lukaszb
Date: 2013-07-10 23:57:04
Summary: Removed obsolates from devenv doc
Affected #: 3 files
diff -r eacb5ca142abf0b855d9ed2f8d61857b43ced268 -r ecb095208e429b8df180c36b4c8e8422acca89a7 doc/config.txt
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -172,15 +172,6 @@
``{toxworkdir}/{envname}``
-.. confval:: package=BOOL
-
- .. versionadded:: 1.5
-
- Set to ``False`` if you don't want tox to perform package-related steps
- (building source distribution and installing it). Might be useful for
- non-package projects (i.e. all that lacks ``setup.py`` file). **default**:
- ``True``.
-
Substitutions
---------------------
diff -r eacb5ca142abf0b855d9ed2f8d61857b43ced268 -r ecb095208e429b8df180c36b4c8e8422acca89a7 doc/example/devenv.txt
--- a/doc/example/devenv.txt
+++ b/doc/example/devenv.txt
@@ -52,6 +52,7 @@
[testenv:devenv]
envdir = devenv
basepython = python2.7
+ deps =
commands =
pip install -r requirements.txt
diff -r eacb5ca142abf0b855d9ed2f8d61857b43ced268 -r ecb095208e429b8df180c36b4c8e8422acca89a7 tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -256,7 +256,6 @@
reader = IniReader(self._cfg, fallbacksections=["testenv"])
reader.addsubstitions(**subs)
vc.envdir = reader.getpath(section, "envdir", "{toxworkdir}/%s" % name)
- vc.package = reader.getbool(section, "package", True)
vc.args_are_paths = reader.getbool(section, "args_are_paths", True)
if reader.getdefault(section, "python", None):
raise tox.exception.ConfigError(
https://bitbucket.org/hpk42/tox/commits/d0fe35302b52/
Changeset: d0fe35302b52
User: hpk42
Date: 2013-07-11 11:13:15
Summary: Merged in lukaszb/tox (pull request #45)
Created initial documentation for development environments -- related with #101
Affected #: 5 files
diff -r 63d37ba9cc8babe926e45f9e8294841148b0451b -r d0fe35302b524186be561fdba90f5a0acc81df92 doc/config.txt
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -176,6 +176,15 @@
(including when installing the project sdist package).
+.. confval:: envdir
+
+ .. versionadded:: 1.5
+
+ User can set specific path for environment. If path would not be absolute it
+ would be treated as relative to ``{toxinidir}``. **default**:
+ ``{toxworkdir}/{envname}``
+
+
Substitutions
---------------------
diff -r 63d37ba9cc8babe926e45f9e8294841148b0451b -r d0fe35302b524186be561fdba90f5a0acc81df92 doc/example/devenv.txt
--- /dev/null
+++ b/doc/example/devenv.txt
@@ -0,0 +1,58 @@
+
+Development environment
+=======================
+
+Tox can be used to prepare development virtual environment for local projects.
+This feature can be useful in order to preserve environment across team members
+working on same project. It can be also used by deployment tools to prepare
+proper environments.
+
+
+Configuration
+-------------
+
+Firstly, you need to prepare configuration for your development environment. In
+order to do that, we must define proper section at ``tox.ini`` file and tell at
+what directory environment should be created. Moreover, we need to specify
+python version that should be picked::
+
+ [testenv:devenv]
+ envdir = devenv
+ basepython = python2.7
+ commands =
+ deps =
+
+
+Actually, you can configure a lot more, those are the only required settings.
+In example you can add ``deps`` and ``commands`` settings. Here, we tell tox
+not to pick ``commands`` or ``deps`` from base ``testenv`` configuration.
+
+
+Creating development environment
+--------------------------------
+
+Once ``devenv`` section is defined we can instrument tox to create our
+environment::
+
+ tox -e devenv
+
+This will create an environment at path specified by ``envdir`` under
+``[testenv:devenv]`` section.
+
+
+Full configuration example
+--------------------------
+
+Let's say we want our development environment sit at ``devenv`` and pull
+packages from ``requirements.txt`` file which we create at the same directory
+as ``tox.ini`` file. We also want to speciy Python version to be 2.7.
+
+Here is example configuration for that::
+
+ [testenv:devenv]
+ envdir = devenv
+ basepython = python2.7
+ deps =
+ commands =
+ pip install -r requirements.txt
+
diff -r 63d37ba9cc8babe926e45f9e8294841148b0451b -r d0fe35302b524186be561fdba90f5a0acc81df92 doc/examples.txt
--- a/doc/examples.txt
+++ b/doc/examples.txt
@@ -11,4 +11,5 @@
example/nose.txt
example/general.txt
example/jenkins.txt
+ example/devenv.txt
diff -r 63d37ba9cc8babe926e45f9e8294841148b0451b -r d0fe35302b524186be561fdba90f5a0acc81df92 tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -44,6 +44,36 @@
assert dep2.indexserver.name == "xyz"
assert dep2.indexserver.url == "xyz_repo"
+ def test_envdir_set_manually(self, tmpdir, newconfig):
+ config = newconfig([], """
+ [testenv:devenv]
+ envdir = devenv
+ """)
+ envconfig = config.envconfigs['devenv']
+ assert envconfig.envdir == tmpdir.join('devenv')
+
+ def test_envdir_set_manually_with_substitutions(self, tmpdir, newconfig):
+ config = newconfig([], """
+ [testenv:devenv]
+ envdir = {toxworkdir}/foobar
+ """)
+ envconfig = config.envconfigs['devenv']
+ assert envconfig.envdir == config.toxworkdir.join('foobar')
+
+ def test_package_flag(self, tmpdir, newconfig):
+ config = newconfig([], """
+ [testenv:py27]
+ """)
+ envconfig = config.envconfigs['py27']
+ assert envconfig.package == True
+
+ config = newconfig([], """
+ [testenv:py27]
+ package = False
+ """)
+ envconfig = config.envconfigs['py27']
+ assert envconfig.package == False
+
class TestConfigPackage:
def test_defaults(self, tmpdir, newconfig):
config = newconfig([], "")
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 notifications at travis-ci.org Thu Jul 11 10:56:20 2013
From: notifications at travis-ci.org (Travis CI)
Date: Thu, 11 Jul 2013 08:56:20 +0000
Subject: [Pytest-commit] [Failed] hpk42/pytest#1 (master - 69ec80a)
Message-ID: <51de73342cad8_2495161688ca@a10c686d-2660-4820-b626-a8d9670fbfb4.mail>
Build Update for hpk42/pytest
-------------------------------------
Build: #1
Status: Failed
Duration: 4 minutes and 36 seconds
Commit: 69ec80a (master)
Author: holger krekel
Message: change copyright years
View the changeset: https://github.com/hpk42/pytest/compare/ef97a75bfab6...69ec80a35136
View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/8958951
--
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 Jul 11 11:30:42 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Thu, 11 Jul 2013 09:30:42 -0000
Subject: [Pytest-commit] commit/pytest: 2 new changesets
Message-ID: <20130711093042.4758.95947@app25.ash-private.bitbucket.org>
2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/d3ec7566fa0a/
Changeset: d3ec7566fa0a
User: bubenkoff
Date: 2013-07-11 11:15:31
Summary: fixes for py25 in test_skipping
Affected #: 2 files
diff -r 9d9f4a158f2f1b8e4094584701eb6e45168d0d7c -r d3ec7566fa0a6fbf5faba45fee1e925f37c4aba0 .gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -29,4 +29,5 @@
.cache
.coverage
.ropeproject
+.idea
diff -r 9d9f4a158f2f1b8e4094584701eb6e45168d0d7c -r d3ec7566fa0a6fbf5faba45fee1e925f37c4aba0 testing/test_skipping.py
--- a/testing/test_skipping.py
+++ b/testing/test_skipping.py
@@ -108,8 +108,7 @@
pass
""")
ev = MarkEvaluator(item, 'skipif')
- with pytest.raises(pytest.fail.Exception) as exc:
- assert ev.istrue()
+ exc = pytest.raises(pytest.fail.Exception, "ev.istrue()")
assert """Failed: you need to specify reason=STRING when using booleans as conditions.""" in exc.value.msg
def test_skipif_class(self, testdir):
https://bitbucket.org/hpk42/pytest/commits/d50722bef5f6/
Changeset: d50722bef5f6
User: hpk42
Date: 2013-07-11 11:30:01
Summary: Merge pull request #2 from bubenkoff/py25-test_skipping_faild
fixes for py25 in test_skipping
Affected #: 2 files
diff -r 5904151239588a7c187932b044c4e480f6965504 -r d50722bef5f6846a2f084b13aa6e486fdcdf8ac1 .gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -29,4 +29,5 @@
.cache
.coverage
.ropeproject
+.idea
diff -r 5904151239588a7c187932b044c4e480f6965504 -r d50722bef5f6846a2f084b13aa6e486fdcdf8ac1 testing/test_skipping.py
--- a/testing/test_skipping.py
+++ b/testing/test_skipping.py
@@ -108,8 +108,7 @@
pass
""")
ev = MarkEvaluator(item, 'skipif')
- with pytest.raises(pytest.fail.Exception) as exc:
- assert ev.istrue()
+ exc = pytest.raises(pytest.fail.Exception, "ev.istrue()")
assert """Failed: you need to specify reason=STRING when using booleans as conditions.""" in exc.value.msg
def test_skipif_class(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 Thu Jul 11 12:08:45 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Thu, 11 Jul 2013 10:08:45 -0000
Subject: [Pytest-commit] commit/pytest: 2 new changesets
Message-ID: <20130711100845.15858.25090@app19.ash-private.bitbucket.org>
2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/8ffc92ebb246/
Changeset: 8ffc92ebb246
User: bubenkoff
Date: 2013-07-11 12:06:13
Summary: correct travis build status image url
Affected #: 1 file
diff -r d50722bef5f6846a2f084b13aa6e486fdcdf8ac1 -r 8ffc92ebb24609352073a8fc8b232d9870daf06e README.rst
--- a/README.rst
+++ b/README.rst
@@ -15,7 +15,7 @@
- many `external plugins `_.
-.. image:: https://secure.travis-ci.org/hpk42/pytest.png?branch=travis-integration
+.. image:: https://secure.travis-ci.org/hpk42/pytest.png
:target: http://travis-ci.org/hpk42/pytest
A simple example for a test::
https://bitbucket.org/hpk42/pytest/commits/a450c7fbb62f/
Changeset: a450c7fbb62f
User: hpk42
Date: 2013-07-11 12:08:27
Summary: Merge pull request #3 from bubenkoff/travis-status-icon
correct travis build status image url
Affected #: 1 file
diff -r d50722bef5f6846a2f084b13aa6e486fdcdf8ac1 -r a450c7fbb62fa93d4b9d0d7b60d7a38fc9fafc14 README.rst
--- a/README.rst
+++ b/README.rst
@@ -15,7 +15,7 @@
- many `external plugins `_.
-.. image:: https://secure.travis-ci.org/hpk42/pytest.png?branch=travis-integration
+.. image:: https://secure.travis-ci.org/hpk42/pytest.png
:target: http://travis-ci.org/hpk42/pytest
A simple example for a 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 notifications at travis-ci.org Thu Jul 11 11:38:54 2013
From: notifications at travis-ci.org (Travis CI)
Date: Thu, 11 Jul 2013 09:38:54 +0000
Subject: [Pytest-commit] [Fixed] hpk42/pytest#3 (master - 29020ea)
Message-ID: <51de7d2dd7d20_22d7874178019@a10c686d-2660-4820-b626-a8d9670fbfb4.mail>
Build Update for hpk42/pytest
-------------------------------------
Build: #3
Status: Fixed
Duration: 7 minutes and 37 seconds
Commit: 29020ea (master)
Author: holger krekel
Message: Merge pull request #2 from bubenkoff/py25-test_skipping_faild
fixes for py25 in test_skipping
View the changeset: https://github.com/hpk42/pytest/compare/69ec80a35136...29020ea04006
View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/8959825
--
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 Jul 11 12:21:04 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Thu, 11 Jul 2013 10:21:04 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: send IRC notifications to
pytest-dev
Message-ID: <20130711102104.27359.31072@app14.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/11e35e2bf007/
Changeset: 11e35e2bf007
User: hpk42
Date: 2013-07-11 12:20:38
Summary: send IRC notifications to pytest-dev
Affected #: 1 file
diff -r a450c7fbb62fa93d4b9d0d7b60d7a38fc9fafc14 -r 11e35e2bf00787903c2d80de3d47f3bf4b8e4106 .travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,6 @@
script: detox --recreate
notifications:
irc:
- - "chat.freenode.net#pylib"
+ - "chat.freenode.net#pytest-dev"
email:
- pytest-commit at python.org
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 Jul 11 16:08:05 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Thu, 11 Jul 2013 14:08:05 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: fix link to kotti
Message-ID: <20130711140805.13330.63718@app23.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/5eca54d508b4/
Changeset: 5eca54d508b4
User: hpk42
Date: 2013-07-11 16:07:58
Summary: fix link to kotti
Affected #: 1 file
diff -r 11e35e2bf00787903c2d80de3d47f3bf4b8e4106 -r 5eca54d508b406369a0836f8f6422fd80a1836db doc/en/projects.txt
--- a/doc/en/projects.txt
+++ b/doc/en/projects.txt
@@ -64,8 +64,8 @@
* `pytest-django `_ for Django
* `zope.pytest `_ for Zope and Grok
-* `pytest__gae `_ for Google App Engine
-* There is `some work `_ underway for Kotti, a CMS built in Pyramid/Pylons
+* `pytest_gae `_ for Google App Engine
+* There is `some work `_ underway for Kotti, a CMS built in Pyramid/Pylons
Some organisations using 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 notifications at travis-ci.org Fri Jul 12 10:36:18 2013
From: notifications at travis-ci.org (Travis CI)
Date: Fri, 12 Jul 2013 08:36:18 +0000
Subject: [Pytest-commit] [Passed] bubenkoff/pytest#6 (coveralls-integrations
- 0b5e384)
Message-ID: <51dfc001f3a70_23a8c4914d@5ab9f7ef-c402-45f9-b3de-e95838f8df90.mail>
Build Update for bubenkoff/pytest
-------------------------------------
Build: #6
Status: Passed
Duration: 8 minutes and 10 seconds
Commit: 0b5e384 (coveralls-integrations)
Author: Anatoly Bubenkov
Message: remove debug print
View the changeset: https://github.com/bubenkoff/pytest/compare/61267680f5f2...0b5e384ea63e
View the full build log and details: https://travis-ci.org/bubenkoff/pytest/builds/8999386
--
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 Fri Jul 12 19:38:26 2013
From: issues-reply at bitbucket.org (Barry Warsaw)
Date: Fri, 12 Jul 2013 17:38:26 -0000
Subject: [Pytest-commit] Issue #105: Hidden dependency on $HOME (hpk42/tox)
Message-ID: <20130712173826.23408.87177@app11.ash-private.bitbucket.org>
New issue 105: Hidden dependency on $HOME
https://bitbucket.org/hpk42/tox/issue/105/hidden-dependency-on-home
Barry Warsaw:
tox appears to have a hidden dependency on a valid $HOME, but in some environments this is not the case. For example, when building the package for Ubuntu, the build environment deliberately sets $HOME to /sbuild-nonexistent. You can reproduce this with hg head by doing:
$ HOME=/sbuild-nonexistent tox
Traceback (most recent call last):
File "/usr/bin/tox", line 9, in
load_entry_point('tox==1.4.2', 'console_scripts', 'tox')()
File "/usr/lib/python2.7/dist-packages/tox/_cmdline.py", line 25, in main
retcode = Session(config).runcommand()
File "/usr/lib/python2.7/dist-packages/tox/_cmdline.py", line 273, in runcommand
return self.subcommand_test()
File "/usr/lib/python2.7/dist-packages/tox/_cmdline.py", line 353, in subcommand_test
sdist_path = self.sdist()
File "/usr/lib/python2.7/dist-packages/tox/_cmdline.py", line 348, in sdist
sdistfile.dirpath().ensure(dir=1)
File "/usr/lib/python2.7/dist-packages/py/_path/local.py", line 424, in ensure
return p._ensuredirs()
File "/usr/lib/python2.7/dist-packages/py/_path/local.py", line 406, in _ensuredirs
parent._ensuredirs()
File "/usr/lib/python2.7/dist-packages/py/_path/local.py", line 406, in _ensuredirs
parent._ensuredirs()
File "/usr/lib/python2.7/dist-packages/py/_path/local.py", line 409, in _ensuredirs
self.mkdir()
File "/usr/lib/python2.7/dist-packages/py/_path/local.py", line 381, in mkdir
py.error.checked_call(os.mkdir, str(p))
File "/usr/lib/python2.7/dist-packages/py/_error.py", line 84, in checked_call
raise cls("%s%r" % (func.__name__, args))
py.error.EACCES: [Permission denied]: mkdir('/sbuild-nonexistent',)
From commits-noreply at bitbucket.org Tue Jul 16 11:29:07 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Tue, 16 Jul 2013 09:29:07 -0000
Subject: [Pytest-commit] commit/tox: hpk42: add new python testing training
date
Message-ID: <20130716092907.28415.40735@app10.ash-private.bitbucket.org>
1 new commit in tox:
https://bitbucket.org/hpk42/tox/commits/2567d6b26c89/
Changeset: 2567d6b26c89
User: hpk42
Date: 2013-07-16 11:29:02
Summary: add new python testing training date
Affected #: 1 file
diff -r d0fe35302b524186be561fdba90f5a0acc81df92 -r 2567d6b26c8995df6cacee337d90f34418057293 doc/index.txt
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -1,8 +1,7 @@
Welcome to the tox automation project
===============================================
-..
- Upcoming: `professional testing with pytest and tox `_ , 24th-26th June 2013, Leipzig.
+.. note:: second training: `professional testing with Python `_ , 25-27th November 2013, Leipzig.
vision: standardize testing in Python
---------------------------------------------
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 Tue Jul 16 15:30:51 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Tue, 16 Jul 2013 13:30:51 -0000
Subject: [Pytest-commit] commit/pytest: 2 new changesets
Message-ID: <20130716133051.5125.21967@app04.ash-private.bitbucket.org>
2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/8a8be3def6c7/
Changeset: 8a8be3def6c7
User: pfctdayelise
Date: 2013-05-29 04:59:47
Summary: A couple of improvements to parametrize
- When not specifying ids, let None and bools use their native string form (like str, int, float) rather than obfuscated form used for objects
- When specifying ids, explicitly raise a ValueError if a different number of ids are specified compared to the test cases
- Add tests for both these items.
Affected #: 2 files
diff -r 5d0b6123d6541ad497cc592d72b9ed50a7c26915 -r 8a8be3def6c70aecaca71b7dae05b14aa73eda59 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -2,6 +2,7 @@
import py
import inspect
import sys
+from types import NoneType
import pytest
from _pytest.main import getfslineno
from _pytest.mark import MarkDecorator, MarkInfo
@@ -705,6 +706,9 @@
raise ValueError("%r uses no fixture %r" %(
self.function, arg))
valtype = indirect and "params" or "funcargs"
+ if ids and len(ids) != len(argvalues):
+ raise ValueError('%d tests specified with %d ids' %(
+ len(argvalues), len(ids)))
if not ids:
ids = idmaker(argnames, argvalues)
newcalls = []
@@ -758,7 +762,7 @@
for valindex, valset in enumerate(argvalues):
this_id = []
for nameindex, val in enumerate(valset):
- if not isinstance(val, (float, int, str)):
+ if not isinstance(val, (float, int, str, bool, NoneType)):
this_id.append(str(argnames[nameindex])+str(valindex))
else:
this_id.append(str(val))
diff -r 5d0b6123d6541ad497cc592d72b9ed50a7c26915 -r 8a8be3def6c70aecaca71b7dae05b14aa73eda59 testing/python/metafunc.py
--- a/testing/python/metafunc.py
+++ b/testing/python/metafunc.py
@@ -95,6 +95,17 @@
ids = [x.id for x in metafunc._calls]
assert ids == ["basic-abc", "basic-def", "advanced-abc", "advanced-def"]
+ def test_parametrize_with_wrong_number_of_ids(self, testdir):
+ def func(x, y): pass
+ metafunc = self.Metafunc(func)
+
+ with pytest.raises(ValueError):
+ metafunc.parametrize("x", [1,2], ids=['basic'])
+
+ with pytest.raises(ValueError):
+ metafunc.parametrize(("x","y"), [("abc", "def"),
+ ("ghi", "jkl")], ids=["one"])
+
def test_parametrize_with_userobjects(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
@@ -121,6 +132,25 @@
result = idmaker((py.builtin._totext("a"), "b"), [({}, '\xc3\xb4')])
assert result == ['a0-\xc3\xb4']
+ def test_idmaker_native_strings(self):
+ from _pytest.python import idmaker
+ result = idmaker(("a", "b"), [(1.0, -1.1),
+ (2, -202),
+ ("three", "three hundred"),
+ (True, False),
+ (None, None),
+ (list("six"), [66, 66]),
+ ({7}, set("seven")),
+ (tuple("eight"), (8, -8, 8))
+ ])
+ assert result == ["1.0--1.1",
+ "2--202",
+ "three-three hundred",
+ "True-False",
+ "None-None",
+ "a5-b5",
+ "a6-b6",
+ "a7-b7"]
def test_addcall_and_parametrize(self):
def func(x, y): pass
@@ -530,8 +560,6 @@
*test_function*1.3-b1*
""")
-
-
@pytest.mark.parametrize(("scope", "length"),
[("module", 2), ("function", 4)])
def test_parametrize_scope_overrides(self, testdir, scope, length):
https://bitbucket.org/hpk42/pytest/commits/7fd344f34e08/
Changeset: 7fd344f34e08
User: hpk42
Date: 2013-07-16 15:30:48
Summary: Merged in pfctdayelise/pytest (pull request #38)
A couple of improvements to parametrize
Affected #: 2 files
diff -r 5eca54d508b406369a0836f8f6422fd80a1836db -r 7fd344f34e088e3d4a6aa47f93901c4d78153c64 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -2,6 +2,7 @@
import py
import inspect
import sys
+from types import NoneType
import pytest
from _pytest.main import getfslineno
from _pytest.mark import MarkDecorator, MarkInfo
@@ -709,6 +710,9 @@
raise ValueError("%r uses no fixture %r" %(
self.function, arg))
valtype = indirect and "params" or "funcargs"
+ if ids and len(ids) != len(argvalues):
+ raise ValueError('%d tests specified with %d ids' %(
+ len(argvalues), len(ids)))
if not ids:
ids = idmaker(argnames, argvalues)
newcalls = []
@@ -762,7 +766,7 @@
for valindex, valset in enumerate(argvalues):
this_id = []
for nameindex, val in enumerate(valset):
- if not isinstance(val, (float, int, str)):
+ if not isinstance(val, (float, int, str, bool, NoneType)):
this_id.append(str(argnames[nameindex])+str(valindex))
else:
this_id.append(str(val))
diff -r 5eca54d508b406369a0836f8f6422fd80a1836db -r 7fd344f34e088e3d4a6aa47f93901c4d78153c64 testing/python/metafunc.py
--- a/testing/python/metafunc.py
+++ b/testing/python/metafunc.py
@@ -95,6 +95,17 @@
ids = [x.id for x in metafunc._calls]
assert ids == ["basic-abc", "basic-def", "advanced-abc", "advanced-def"]
+ def test_parametrize_with_wrong_number_of_ids(self, testdir):
+ def func(x, y): pass
+ metafunc = self.Metafunc(func)
+
+ with pytest.raises(ValueError):
+ metafunc.parametrize("x", [1,2], ids=['basic'])
+
+ with pytest.raises(ValueError):
+ metafunc.parametrize(("x","y"), [("abc", "def"),
+ ("ghi", "jkl")], ids=["one"])
+
def test_parametrize_with_userobjects(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
@@ -121,6 +132,25 @@
result = idmaker((py.builtin._totext("a"), "b"), [({}, '\xc3\xb4')])
assert result == ['a0-\xc3\xb4']
+ def test_idmaker_native_strings(self):
+ from _pytest.python import idmaker
+ result = idmaker(("a", "b"), [(1.0, -1.1),
+ (2, -202),
+ ("three", "three hundred"),
+ (True, False),
+ (None, None),
+ (list("six"), [66, 66]),
+ ({7}, set("seven")),
+ (tuple("eight"), (8, -8, 8))
+ ])
+ assert result == ["1.0--1.1",
+ "2--202",
+ "three-three hundred",
+ "True-False",
+ "None-None",
+ "a5-b5",
+ "a6-b6",
+ "a7-b7"]
def test_addcall_and_parametrize(self):
def func(x, y): pass
@@ -530,8 +560,6 @@
*test_function*1.3-b1*
""")
-
-
@pytest.mark.parametrize(("scope", "length"),
[("module", 2), ("function", 4)])
def test_parametrize_scope_overrides(self, testdir, scope, length):
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 Tue Jul 16 16:08:55 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Tue, 16 Jul 2013 14:08:55 -0000
Subject: [Pytest-commit] commit/pytest: 3 new changesets
Message-ID: <20130716140855.15813.97465@app15.ash-private.bitbucket.org>
3 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/434928c9c3da/
Changeset: 434928c9c3da
User: hpk42
Date: 2013-07-16 11:30:21
Summary: add python testing training
Affected #: 1 file
diff -r 5eca54d508b406369a0836f8f6422fd80a1836db -r 434928c9c3da6c841b8a80381da5bbd61ac5a694 doc/en/index.txt
--- a/doc/en/index.txt
+++ b/doc/en/index.txt
@@ -1,6 +1,8 @@
.. _features:
+.. note:: second training: `professional testing with Python `_ , 25-27th November 2013, Leipzig.
+
pytest: helps you write better programs
=============================================
https://bitbucket.org/hpk42/pytest/commits/f3c0eb5de5f5/
Changeset: f3c0eb5de5f5
User: hpk42
Date: 2013-07-16 15:32:05
Summary: merge better parametrize error messages, thanks Brianna Laugher
Affected #: 3 files
diff -r 434928c9c3da6c841b8a80381da5bbd61ac5a694 -r f3c0eb5de5f5b6782c7da20131602805d008d476 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -56,6 +56,7 @@
- fix issue307 - use yaml.safe_load in example, thanks Mark Eichin.
+- better parametrize error messages, thanks Brianna Laugher
Changes between 2.3.4 and 2.3.5
-----------------------------------
diff -r 434928c9c3da6c841b8a80381da5bbd61ac5a694 -r f3c0eb5de5f5b6782c7da20131602805d008d476 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -2,6 +2,7 @@
import py
import inspect
import sys
+from types import NoneType
import pytest
from _pytest.main import getfslineno
from _pytest.mark import MarkDecorator, MarkInfo
@@ -709,6 +710,9 @@
raise ValueError("%r uses no fixture %r" %(
self.function, arg))
valtype = indirect and "params" or "funcargs"
+ if ids and len(ids) != len(argvalues):
+ raise ValueError('%d tests specified with %d ids' %(
+ len(argvalues), len(ids)))
if not ids:
ids = idmaker(argnames, argvalues)
newcalls = []
@@ -762,7 +766,7 @@
for valindex, valset in enumerate(argvalues):
this_id = []
for nameindex, val in enumerate(valset):
- if not isinstance(val, (float, int, str)):
+ if not isinstance(val, (float, int, str, bool, NoneType)):
this_id.append(str(argnames[nameindex])+str(valindex))
else:
this_id.append(str(val))
diff -r 434928c9c3da6c841b8a80381da5bbd61ac5a694 -r f3c0eb5de5f5b6782c7da20131602805d008d476 testing/python/metafunc.py
--- a/testing/python/metafunc.py
+++ b/testing/python/metafunc.py
@@ -95,6 +95,17 @@
ids = [x.id for x in metafunc._calls]
assert ids == ["basic-abc", "basic-def", "advanced-abc", "advanced-def"]
+ def test_parametrize_with_wrong_number_of_ids(self, testdir):
+ def func(x, y): pass
+ metafunc = self.Metafunc(func)
+
+ with pytest.raises(ValueError):
+ metafunc.parametrize("x", [1,2], ids=['basic'])
+
+ with pytest.raises(ValueError):
+ metafunc.parametrize(("x","y"), [("abc", "def"),
+ ("ghi", "jkl")], ids=["one"])
+
def test_parametrize_with_userobjects(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
@@ -121,6 +132,25 @@
result = idmaker((py.builtin._totext("a"), "b"), [({}, '\xc3\xb4')])
assert result == ['a0-\xc3\xb4']
+ def test_idmaker_native_strings(self):
+ from _pytest.python import idmaker
+ result = idmaker(("a", "b"), [(1.0, -1.1),
+ (2, -202),
+ ("three", "three hundred"),
+ (True, False),
+ (None, None),
+ (list("six"), [66, 66]),
+ ({7}, set("seven")),
+ (tuple("eight"), (8, -8, 8))
+ ])
+ assert result == ["1.0--1.1",
+ "2--202",
+ "three-three hundred",
+ "True-False",
+ "None-None",
+ "a5-b5",
+ "a6-b6",
+ "a7-b7"]
def test_addcall_and_parametrize(self):
def func(x, y): pass
@@ -530,8 +560,6 @@
*test_function*1.3-b1*
""")
-
-
@pytest.mark.parametrize(("scope", "length"),
[("module", 2), ("function", 4)])
def test_parametrize_scope_overrides(self, testdir, scope, length):
https://bitbucket.org/hpk42/pytest/commits/6e5fd004c38d/
Changeset: 6e5fd004c38d
User: hpk42
Date: 2013-07-16 15:43:20
Summary: some python2.5/3.3 fixes of Brianna's parametrize improvements
Affected #: 4 files
diff -r f3c0eb5de5f5b6782c7da20131602805d008d476 -r 6e5fd004c38df785e08fdad5d7eaf3095b8fbd0f _pytest/__init__.py
--- a/_pytest/__init__.py
+++ b/_pytest/__init__.py
@@ -1,2 +1,2 @@
#
-__version__ = '2.4.0.dev5'
+__version__ = '2.4.0.dev6'
diff -r f3c0eb5de5f5b6782c7da20131602805d008d476 -r 6e5fd004c38df785e08fdad5d7eaf3095b8fbd0f _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -2,7 +2,6 @@
import py
import inspect
import sys
-from types import NoneType
import pytest
from _pytest.main import getfslineno
from _pytest.mark import MarkDecorator, MarkInfo
@@ -12,6 +11,8 @@
import _pytest
cutdir = py.path.local(_pytest.__file__).dirpath()
+NoneType = type(None)
+
callable = py.builtin.callable
def getimfunc(func):
diff -r f3c0eb5de5f5b6782c7da20131602805d008d476 -r 6e5fd004c38df785e08fdad5d7eaf3095b8fbd0f setup.py
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,7 @@
name='pytest',
description='py.test: simple powerful testing with Python',
long_description = long_description,
- version='2.4.0.dev5',
+ version='2.4.0.dev6',
url='http://pytest.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
diff -r f3c0eb5de5f5b6782c7da20131602805d008d476 -r 6e5fd004c38df785e08fdad5d7eaf3095b8fbd0f testing/python/metafunc.py
--- a/testing/python/metafunc.py
+++ b/testing/python/metafunc.py
@@ -99,12 +99,12 @@
def func(x, y): pass
metafunc = self.Metafunc(func)
- with pytest.raises(ValueError):
- metafunc.parametrize("x", [1,2], ids=['basic'])
+ pytest.raises(ValueError, lambda:
+ metafunc.parametrize("x", [1,2], ids=['basic']))
- with pytest.raises(ValueError):
+ pytest.raises(ValueError, lambda:
metafunc.parametrize(("x","y"), [("abc", "def"),
- ("ghi", "jkl")], ids=["one"])
+ ("ghi", "jkl")], ids=["one"]))
def test_parametrize_with_userobjects(self):
def func(x, y): pass
@@ -140,7 +140,7 @@
(True, False),
(None, None),
(list("six"), [66, 66]),
- ({7}, set("seven")),
+ (set([7]), set("seven")),
(tuple("eight"), (8, -8, 8))
])
assert result == ["1.0--1.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 Tue Jul 16 17:01:41 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Tue, 16 Jul 2013 15:01:41 -0000
Subject: [Pytest-commit] commit/tox: 9 new changesets
Message-ID: <20130716150141.648.17875@app09.ash-private.bitbucket.org>
9 new commits in tox:
https://bitbucket.org/hpk42/tox/commits/14d597656e37/
Changeset: 14d597656e37
User: mordred
Date: 2013-07-10 22:22:16
Summary: Add option to skip sdist step.
First change in a sequence to allow for customization of operational
steps. The sdist creation is current unconditional, which for some
projects makes running tests unreasonably slow. For instance, OpenStack
would prefer to just have python setup.py develop run - but we'd like
to put in the support in a flexible way that will allow people to
express the pipeline needs of their project.
Affected #: 4 files
diff -r 63d37ba9cc8babe926e45f9e8294841148b0451b -r 14d597656e378d1abd515bf90076704824b0f9fe doc/config.txt
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -21,6 +21,7 @@
distdir=path # defaults to {toxworkdir}/dist
distshare=path # defaults to {homedir}/.tox/distshare
envlist=ENVLIST # defaults to the list of all environments
+ skipsdist=BOOL # defaults to false
``tox`` autodetects if it is running in a Jenkins_ context
diff -r 63d37ba9cc8babe926e45f9e8294841148b0451b -r 14d597656e378d1abd515bf90076704824b0f9fe tests/test_z_cmdline.py
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -252,6 +252,23 @@
"*ERROR*unknown*environment*qpwoei*",
])
+def test_skip_sdist(cmd, initproj):
+ initproj("pkg123-0.7", filedefs={
+ 'tests': {'test_hello.py': "def test_hello(): pass"},
+ 'setup.py': """
+ syntax error
+ """
+ ,
+ 'tox.ini': '''
+ [tox]
+ skipsdist=True
+ [testenv]
+ commands=echo done
+ '''
+ })
+ result = cmd.run("tox", )
+ assert result.ret == 0
+
def test_sdist_fails(cmd, initproj):
initproj("pkg123-0.7", filedefs={
'tests': {'test_hello.py': "def test_hello(): pass"},
diff -r 63d37ba9cc8babe926e45f9e8294841148b0451b -r 14d597656e378d1abd515bf90076704824b0f9fe tox/_cmdline.py
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -362,19 +362,24 @@
return sdist_path
def subcommand_test(self):
- sdist_path = self.sdist()
- if not sdist_path:
- return 2
+ if self.config.skipsdist:
+ self.report.info("skipping sdist step")
+ sdist_path = None
+ else:
+ sdist_path = self.sdist()
+ if not sdist_path:
+ return 2
if self.config.option.sdistonly:
return
for venv in self.venvlist:
if self.setupenv(venv):
- self.installpkg(venv, sdist_path)
- self.runtestenv(venv, sdist_path)
+ if not self.config.skipsdist:
+ self.installpkg(venv, sdist_path)
+ self.runtestenv(venv)
retcode = self._summary()
return retcode
- def runtestenv(self, venv, sdist_path, redirect=False):
+ def runtestenv(self, venv, redirect=False):
if not self.config.option.notest:
if venv.status:
return
@@ -408,6 +413,7 @@
self.report.keyvalue("toxworkdir: ", self.config.toxworkdir)
self.report.keyvalue("setupdir: ", self.config.setupdir)
self.report.keyvalue("distshare: ", self.config.distshare)
+ self.report.keyvalue("skipsdist: ", self.config.skipsdist)
self.report.tw.line()
for envconfig in self.config.envconfigs.values():
self.report.line("[testenv:%s]" % envconfig.envname, bold=True)
diff -r 63d37ba9cc8babe926e45f9e8294841148b0451b -r 14d597656e378d1abd515bf90076704824b0f9fe tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -194,6 +194,7 @@
homedir=config.homedir)
config.toxworkdir = reader.getpath(toxsection, "toxworkdir",
"{toxinidir}/.tox")
+ config.skipsdist = reader.getbool(toxsection, "skipsdist", False)
config.minversion = reader.getdefault(toxsection, "minversion", None)
# determine indexserver dictionary
https://bitbucket.org/hpk42/tox/commits/517fca71add7/
Changeset: 517fca71add7
User: mordred
Date: 2013-07-10 22:44:42
Summary: Make sure that the venv is finalized.
Skipping sdist causes the config to not be saved, which causes
recreation next time.
Affected #: 2 files
diff -r 14d597656e378d1abd515bf90076704824b0f9fe -r 517fca71add7ed6d191ce04206109c6eceabc58d tox/_cmdline.py
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -327,6 +327,12 @@
return False
return True
+ def finishvenv(self, venv):
+ action = self.newaction(venv, "finishvenv")
+ with action:
+ venv.finish()
+ return True
+
def installpkg(self, venv, sdist_path):
action = self.newaction(venv, "installpkg", sdist_path)
with action:
@@ -375,6 +381,8 @@
if self.setupenv(venv):
if not self.config.skipsdist:
self.installpkg(venv, sdist_path)
+ else:
+ self.finishvenv(venv)
self.runtestenv(venv)
retcode = self._summary()
return retcode
diff -r 14d597656e378d1abd515bf90076704824b0f9fe -r 517fca71add7ed6d191ce04206109c6eceabc58d tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -197,11 +197,14 @@
self._pcall(args, venv=False, action=action, cwd=basepath)
self.just_created = True
+ def finish(self):
+ self._getliveconfig().writeconfig(self.path_config)
+
def installpkg(self, sdistpath, action):
assert action is not None
if getattr(self, 'just_created', False):
action.setactivity("inst", sdistpath)
- self._getliveconfig().writeconfig(self.path_config)
+ self.finish()
extraopts = []
else:
action.setactivity("inst-nodeps", sdistpath)
https://bitbucket.org/hpk42/tox/commits/5464e3062afa/
Changeset: 5464e3062afa
User: mordred
Date: 2013-07-10 23:41:45
Summary: Add support for installing via setup.py develop.
Affected #: 4 files
diff -r 517fca71add7ed6d191ce04206109c6eceabc58d -r 5464e3062afa62ef2731fcc63902041adaffa56f doc/config.txt
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -22,6 +22,7 @@
distshare=path # defaults to {homedir}/.tox/distshare
envlist=ENVLIST # defaults to the list of all environments
skipsdist=BOOL # defaults to false
+ usedevelop=BOOL # use python setup.py develop, defaults to false
``tox`` autodetects if it is running in a Jenkins_ context
diff -r 517fca71add7ed6d191ce04206109c6eceabc58d -r 5464e3062afa62ef2731fcc63902041adaffa56f tox/_cmdline.py
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -333,6 +333,16 @@
venv.finish()
return True
+ def developpkg(self, venv, setupdir):
+ action = self.newaction(venv, "developpkg", setupdir)
+ with action:
+ try:
+ venv.developpkg(setupdir, action)
+ return True
+ except tox.exception.InvocationError:
+ venv.status = sys.exc_info()[1]
+ return False
+
def installpkg(self, venv, sdist_path):
action = self.newaction(venv, "installpkg", sdist_path)
with action:
@@ -379,10 +389,12 @@
return
for venv in self.venvlist:
if self.setupenv(venv):
- if not self.config.skipsdist:
+ if self.config.skipsdist:
+ if self.config.usedevelop:
+ self.developpkg(venv, self.config.setupdir)
+ self.finishvenv(venv)
+ else:
self.installpkg(venv, sdist_path)
- else:
- self.finishvenv(venv)
self.runtestenv(venv)
retcode = self._summary()
return retcode
@@ -422,6 +434,7 @@
self.report.keyvalue("setupdir: ", self.config.setupdir)
self.report.keyvalue("distshare: ", self.config.distshare)
self.report.keyvalue("skipsdist: ", self.config.skipsdist)
+ self.report.keyvalue("usedevelop: ", self.config.usedevelop)
self.report.tw.line()
for envconfig in self.config.envconfigs.values():
self.report.line("[testenv:%s]" % envconfig.envname, bold=True)
diff -r 517fca71add7ed6d191ce04206109c6eceabc58d -r 5464e3062afa62ef2731fcc63902041adaffa56f tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -194,7 +194,9 @@
homedir=config.homedir)
config.toxworkdir = reader.getpath(toxsection, "toxworkdir",
"{toxinidir}/.tox")
- config.skipsdist = reader.getbool(toxsection, "skipsdist", False)
+ config.usedevelop = reader.getbool(toxsection, "usedevelop", False)
+ config.skipsdist = reader.getbool(
+ toxsection, "skipsdist", config.usedevelop)
config.minversion = reader.getdefault(toxsection, "minversion", None)
# determine indexserver dictionary
diff -r 517fca71add7ed6d191ce04206109c6eceabc58d -r 5464e3062afa62ef2731fcc63902041adaffa56f tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -1,4 +1,5 @@
from __future__ import with_statement
+import subprocess
import sys, os, re
import py
import tox
@@ -200,6 +201,29 @@
def finish(self):
self._getliveconfig().writeconfig(self.path_config)
+ def _needs_reinstall(self, setupdir, action):
+ setup_py = setupdir.join('setup.py')
+ setup_cfg = setupdir.join('setup.cfg')
+ args = [str(self.getconfigexecutable()), str(setup_py), '--name']
+ output = subprocess.Popen(args, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out = output.communicate()
+ name = out[0].strip().decode('utf-8')
+ egg_info = setupdir.join('.'.join((name, 'egg-info')))
+ for conf_file in (setup_py, setup_cfg):
+ if (conf_file.check()
+ and conf_file.mtime() > egg_info.mtime()):
+ return True
+ return False
+
+ def developpkg(self, setupdir, action):
+ assert action is not None
+ self.finish()
+ if not self._needs_reinstall(setupdir, action):
+ return
+ extraopts = ['--no-deps']
+ self._install(['-e', setupdir], extraopts=extraopts, action=action)
+
def installpkg(self, sdistpath, action):
assert action is not None
if getattr(self, 'just_created', False):
https://bitbucket.org/hpk42/tox/commits/94ec2412ae39/
Changeset: 94ec2412ae39
User: mordred
Date: 2013-07-11 17:29:51
Summary: Address code review comments
Use action.popen instead of subprocess.popen.
Allow skipsdist=False and usedevelop=True to coexist.
Affected #: 2 files
diff -r 5464e3062afa62ef2731fcc63902041adaffa56f -r 94ec2412ae399eb7a75031a412c42e94dc572896 tox/_cmdline.py
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -73,7 +73,7 @@
f.flush()
return f
- def popen(self, args, cwd=None, env=None, redirect=True):
+ def popen(self, args, cwd=None, env=None, redirect=True, returnout=False):
logged_command = "%s$ %s" %(cwd, " ".join(map(str, args)))
f = outpath = None
if redirect:
@@ -82,6 +82,8 @@
self.id, self.msg, args, env))
f.flush()
self.popen_outpath = outpath = py.path.local(f.name)
+ elif returnout:
+ f = subprocess.PIPE
if cwd is None:
# XXX cwd = self.session.config.cwd
cwd = py.path.local()
@@ -389,9 +391,9 @@
return
for venv in self.venvlist:
if self.setupenv(venv):
- if self.config.skipsdist:
- if self.config.usedevelop:
- self.developpkg(venv, self.config.setupdir)
+ if self.config.usedevelop:
+ self.developpkg(venv, self.config.setupdir)
+ elif self.config.skipsdist:
self.finishvenv(venv)
else:
self.installpkg(venv, sdist_path)
diff -r 5464e3062afa62ef2731fcc63902041adaffa56f -r 94ec2412ae399eb7a75031a412c42e94dc572896 tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -1,5 +1,4 @@
from __future__ import with_statement
-import subprocess
import sys, os, re
import py
import tox
@@ -205,10 +204,9 @@
setup_py = setupdir.join('setup.py')
setup_cfg = setupdir.join('setup.cfg')
args = [str(self.getconfigexecutable()), str(setup_py), '--name']
- output = subprocess.Popen(args, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out = output.communicate()
- name = out[0].strip().decode('utf-8')
+ output = action.popen(args, cwd=setupdir, redirect=False,
+ returnout=True)
+ name = output.strip().decode('utf-8')
egg_info = setupdir.join('.'.join((name, 'egg-info')))
for conf_file in (setup_py, setup_cfg):
if (conf_file.check()
https://bitbucket.org/hpk42/tox/commits/fea763e691c0/
Changeset: fea763e691c0
User: mordred
Date: 2013-07-11 17:36:21
Summary: Add test to use usedevelop
While we're at it, fix the error that adding the test found.
Affected #: 2 files
diff -r 94ec2412ae399eb7a75031a412c42e94dc572896 -r fea763e691c022b6eb2de49e26d5d78462ad8614 tests/test_z_cmdline.py
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -359,6 +359,59 @@
])
+def test_test_develop(cmd, initproj):
+ initproj("example123-0.5", filedefs={
+ 'tests': {'test_hello.py': """
+ def test_hello(pytestconfig):
+ pass
+ """,
+ },
+ 'tox.ini': '''
+ [tox]
+ usedevelop=True
+ [testenv]
+ changedir=tests
+ commands=
+ py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml []
+ deps=pytest
+ '''
+ })
+ result = cmd.run("tox")
+ assert not result.ret
+ result.stdout.fnmatch_lines([
+ "*junit-python.xml*",
+ "*1 passed*",
+ ])
+ result = cmd.run("tox", "-epython", )
+ assert not result.ret
+ result.stdout.fnmatch_lines([
+ "*1 passed*",
+ "*summary*",
+ "*python: commands succeeded"
+ ])
+ # see that things work with a different CWD
+ old = cmd.tmpdir.chdir()
+ result = cmd.run("tox", "-c", "example123/tox.ini")
+ assert not result.ret
+ result.stdout.fnmatch_lines([
+ "*1 passed*",
+ "*summary*",
+ "*python: commands succeeded"
+ ])
+ old.chdir()
+ # see that tests can also fail and retcode is correct
+ testfile = py.path.local("tests").join("test_hello.py")
+ assert testfile.check()
+ testfile.write("def test_fail(): assert 0")
+ result = cmd.run("tox", )
+ assert result.ret
+ result.stdout.fnmatch_lines([
+ "*1 failed*",
+ "*summary*",
+ "*python: *failed*",
+ ])
+
+
def test_test_piphelp(initproj, cmd):
initproj("example123", filedefs={'tox.ini': """
# content of: tox.ini
diff -r 94ec2412ae399eb7a75031a412c42e94dc572896 -r fea763e691c022b6eb2de49e26d5d78462ad8614 tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -209,8 +209,8 @@
name = output.strip().decode('utf-8')
egg_info = setupdir.join('.'.join((name, 'egg-info')))
for conf_file in (setup_py, setup_cfg):
- if (conf_file.check()
- and conf_file.mtime() > egg_info.mtime()):
+ if (not egg_info.check() or (conf_file.check()
+ and conf_file.mtime() > egg_info.mtime())):
return True
return False
https://bitbucket.org/hpk42/tox/commits/6a52c1c93e08/
Changeset: 6a52c1c93e08
User: mordred
Date: 2013-07-11 17:47:44
Summary: Add example documentation for usedevelop
Affected #: 1 file
diff -r fea763e691c022b6eb2de49e26d5d78462ad8614 -r 6a52c1c93e083f760e46f24219a91ba9f69b926f doc/example/general.txt
--- a/doc/example/general.txt
+++ b/doc/example/general.txt
@@ -144,4 +144,37 @@
[testenv:py27]
basepython=/my/path/to/python2.7
+Avoiding expensive sdist
+------------------------
+
+Some projects are large enough that running and sdist, followed by
+an install everytime can be prohibitively costly. To solve this,
+there are two different options you can add to the ``tox`` section. First,
+you can simply ask tox to please not make an sdist::
+
+ [tox]
+ skipsdist=True
+
+If you do this, your local software package will not be installed into
+the virtualenv. You should probably be ok with that, or take steps
+to deal with it in your commands section::
+
+ [testenv]
+ commands =
+ python setup.py develop
+ py.test
+
+Running setup.py develop is a common enough model that it has its own option::
+
+ [tox]
+ usedevelop=True
+
+Which will set ``skipsdist`` to True and then perform the ``setup.py develop``
+step at the place where ``tox`` normally perfoms the installation of the sdist.
+Specifically, it actually runs ``pip install -e .`` behind the scenes, which
+itself calls ``setup.py develop``.
+
+There is an optimization coded in to not bother re-running the command if
+``$projectname.egg-info`` is newer than ``setup.py`` or ``setup.cfg``.
+
.. include:: ../links.txt
https://bitbucket.org/hpk42/tox/commits/ddda508fcee1/
Changeset: ddda508fcee1
User: mordred
Date: 2013-07-16 16:56:23
Summary: Add command line option for develop
Affected #: 3 files
diff -r 6a52c1c93e083f760e46f24219a91ba9f69b926f -r ddda508fcee1c7f91d465b5420a25b6b2b9554ef tests/test_z_cmdline.py
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -359,7 +359,14 @@
])
-def test_test_develop(cmd, initproj):
+def test_develop(initproj, cmd):
+ initproj("example123", filedefs={'tox.ini': """
+ """})
+ result = cmd.run("tox", "-v", "--develop")
+ assert not result.ret
+ assert "sdist-make" not in result.stdout.str()
+
+def test_test_usedevelop(cmd, initproj):
initproj("example123-0.5", filedefs={
'tests': {'test_hello.py': """
def test_hello(pytestconfig):
@@ -376,12 +383,13 @@
deps=pytest
'''
})
- result = cmd.run("tox")
+ result = cmd.run("tox", "-v")
assert not result.ret
result.stdout.fnmatch_lines([
"*junit-python.xml*",
"*1 passed*",
])
+ assert "sdist-make" not in result.stdout.str()
result = cmd.run("tox", "-epython", )
assert not result.ret
result.stdout.fnmatch_lines([
diff -r 6a52c1c93e083f760e46f24219a91ba9f69b926f -r ddda508fcee1c7f91d465b5420a25b6b2b9554ef tox/_cmdline.py
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -391,7 +391,7 @@
return
for venv in self.venvlist:
if self.setupenv(venv):
- if self.config.usedevelop:
+ if self.config.usedevelop or self.config.option.develop:
self.developpkg(venv, self.config.setupdir)
elif self.config.skipsdist:
self.finishvenv(venv)
diff -r 6a52c1c93e083f760e46f24219a91ba9f69b926f -r ddda508fcee1c7f91d465b5420a25b6b2b9554ef tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -90,6 +90,8 @@
help="skip invoking test commands.")
parser.add_argument("--sdistonly", action="store_true", dest="sdistonly",
help="only perform the sdist packaging activity.")
+ parser.add_argument("--develop", action="store_true", dest="develop",
+ help="install package in the venv using setup.py develop")
parser.add_argument("--installpkg", action="store", default=None,
help="use specified package for installation into venv")
parser.add_argument('-i', action="append",
@@ -195,8 +197,9 @@
config.toxworkdir = reader.getpath(toxsection, "toxworkdir",
"{toxinidir}/.tox")
config.usedevelop = reader.getbool(toxsection, "usedevelop", False)
- config.skipsdist = reader.getbool(
- toxsection, "skipsdist", config.usedevelop)
+ config.skipsdist = reader.getbool(toxsection, "skipsdist",
+ config.usedevelop
+ or config.option.develop)
config.minversion = reader.getdefault(toxsection, "minversion", None)
# determine indexserver dictionary
https://bitbucket.org/hpk42/tox/commits/dc7637581d8a/
Changeset: dc7637581d8a
User: mordred
Date: 2013-07-16 16:58:20
Summary: Add documentation for the --develop option
Affected #: 1 file
diff -r ddda508fcee1c7f91d465b5420a25b6b2b9554ef -r dc7637581d8ad1a3793f9b894ffb0a8f758524ed doc/example/general.txt
--- a/doc/example/general.txt
+++ b/doc/example/general.txt
@@ -169,7 +169,8 @@
[tox]
usedevelop=True
-Which will set ``skipsdist`` to True and then perform the ``setup.py develop``
+And a corresponding command line option ``--develop``, which will set
+``skipsdist`` to True and then perform the ``setup.py develop``
step at the place where ``tox`` normally perfoms the installation of the sdist.
Specifically, it actually runs ``pip install -e .`` behind the scenes, which
itself calls ``setup.py develop``.
https://bitbucket.org/hpk42/tox/commits/bfc4a27950dc/
Changeset: bfc4a27950dc
User: hpk42
Date: 2013-07-16 17:01:38
Summary: Merged in mordred/configurable-hooks (pull request #49)
Make software installation more configurable
Affected #: 6 files
diff -r 2567d6b26c8995df6cacee337d90f34418057293 -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 doc/config.txt
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -21,6 +21,8 @@
distdir=path # defaults to {toxworkdir}/dist
distshare=path # defaults to {homedir}/.tox/distshare
envlist=ENVLIST # defaults to the list of all environments
+ skipsdist=BOOL # defaults to false
+ usedevelop=BOOL # use python setup.py develop, defaults to false
``tox`` autodetects if it is running in a Jenkins_ context
diff -r 2567d6b26c8995df6cacee337d90f34418057293 -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 doc/example/general.txt
--- a/doc/example/general.txt
+++ b/doc/example/general.txt
@@ -144,4 +144,38 @@
[testenv:py27]
basepython=/my/path/to/python2.7
+Avoiding expensive sdist
+------------------------
+
+Some projects are large enough that running and sdist, followed by
+an install everytime can be prohibitively costly. To solve this,
+there are two different options you can add to the ``tox`` section. First,
+you can simply ask tox to please not make an sdist::
+
+ [tox]
+ skipsdist=True
+
+If you do this, your local software package will not be installed into
+the virtualenv. You should probably be ok with that, or take steps
+to deal with it in your commands section::
+
+ [testenv]
+ commands =
+ python setup.py develop
+ py.test
+
+Running setup.py develop is a common enough model that it has its own option::
+
+ [tox]
+ usedevelop=True
+
+And a corresponding command line option ``--develop``, which will set
+``skipsdist`` to True and then perform the ``setup.py develop``
+step at the place where ``tox`` normally perfoms the installation of the sdist.
+Specifically, it actually runs ``pip install -e .`` behind the scenes, which
+itself calls ``setup.py develop``.
+
+There is an optimization coded in to not bother re-running the command if
+``$projectname.egg-info`` is newer than ``setup.py`` or ``setup.cfg``.
+
.. include:: ../links.txt
diff -r 2567d6b26c8995df6cacee337d90f34418057293 -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 tests/test_z_cmdline.py
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -252,6 +252,23 @@
"*ERROR*unknown*environment*qpwoei*",
])
+def test_skip_sdist(cmd, initproj):
+ initproj("pkg123-0.7", filedefs={
+ 'tests': {'test_hello.py': "def test_hello(): pass"},
+ 'setup.py': """
+ syntax error
+ """
+ ,
+ 'tox.ini': '''
+ [tox]
+ skipsdist=True
+ [testenv]
+ commands=echo done
+ '''
+ })
+ result = cmd.run("tox", )
+ assert result.ret == 0
+
def test_sdist_fails(cmd, initproj):
initproj("pkg123-0.7", filedefs={
'tests': {'test_hello.py': "def test_hello(): pass"},
@@ -342,6 +359,67 @@
])
+def test_develop(initproj, cmd):
+ initproj("example123", filedefs={'tox.ini': """
+ """})
+ result = cmd.run("tox", "-v", "--develop")
+ assert not result.ret
+ assert "sdist-make" not in result.stdout.str()
+
+def test_test_usedevelop(cmd, initproj):
+ initproj("example123-0.5", filedefs={
+ 'tests': {'test_hello.py': """
+ def test_hello(pytestconfig):
+ pass
+ """,
+ },
+ 'tox.ini': '''
+ [tox]
+ usedevelop=True
+ [testenv]
+ changedir=tests
+ commands=
+ py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml []
+ deps=pytest
+ '''
+ })
+ result = cmd.run("tox", "-v")
+ assert not result.ret
+ result.stdout.fnmatch_lines([
+ "*junit-python.xml*",
+ "*1 passed*",
+ ])
+ assert "sdist-make" not in result.stdout.str()
+ result = cmd.run("tox", "-epython", )
+ assert not result.ret
+ result.stdout.fnmatch_lines([
+ "*1 passed*",
+ "*summary*",
+ "*python: commands succeeded"
+ ])
+ # see that things work with a different CWD
+ old = cmd.tmpdir.chdir()
+ result = cmd.run("tox", "-c", "example123/tox.ini")
+ assert not result.ret
+ result.stdout.fnmatch_lines([
+ "*1 passed*",
+ "*summary*",
+ "*python: commands succeeded"
+ ])
+ old.chdir()
+ # see that tests can also fail and retcode is correct
+ testfile = py.path.local("tests").join("test_hello.py")
+ assert testfile.check()
+ testfile.write("def test_fail(): assert 0")
+ result = cmd.run("tox", )
+ assert result.ret
+ result.stdout.fnmatch_lines([
+ "*1 failed*",
+ "*summary*",
+ "*python: *failed*",
+ ])
+
+
def test_test_piphelp(initproj, cmd):
initproj("example123", filedefs={'tox.ini': """
# content of: tox.ini
diff -r 2567d6b26c8995df6cacee337d90f34418057293 -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 tox/_cmdline.py
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -73,7 +73,7 @@
f.flush()
return f
- def popen(self, args, cwd=None, env=None, redirect=True):
+ def popen(self, args, cwd=None, env=None, redirect=True, returnout=False):
logged_command = "%s$ %s" %(cwd, " ".join(map(str, args)))
f = outpath = None
if redirect:
@@ -82,6 +82,8 @@
self.id, self.msg, args, env))
f.flush()
self.popen_outpath = outpath = py.path.local(f.name)
+ elif returnout:
+ f = subprocess.PIPE
if cwd is None:
# XXX cwd = self.session.config.cwd
cwd = py.path.local()
@@ -327,6 +329,22 @@
return False
return True
+ def finishvenv(self, venv):
+ action = self.newaction(venv, "finishvenv")
+ with action:
+ venv.finish()
+ return True
+
+ def developpkg(self, venv, setupdir):
+ action = self.newaction(venv, "developpkg", setupdir)
+ with action:
+ try:
+ venv.developpkg(setupdir, action)
+ return True
+ except tox.exception.InvocationError:
+ venv.status = sys.exc_info()[1]
+ return False
+
def installpkg(self, venv, sdist_path):
action = self.newaction(venv, "installpkg", sdist_path)
with action:
@@ -362,19 +380,28 @@
return sdist_path
def subcommand_test(self):
- sdist_path = self.sdist()
- if not sdist_path:
- return 2
+ if self.config.skipsdist:
+ self.report.info("skipping sdist step")
+ sdist_path = None
+ else:
+ sdist_path = self.sdist()
+ if not sdist_path:
+ return 2
if self.config.option.sdistonly:
return
for venv in self.venvlist:
if self.setupenv(venv):
- self.installpkg(venv, sdist_path)
- self.runtestenv(venv, sdist_path)
+ if self.config.usedevelop or self.config.option.develop:
+ self.developpkg(venv, self.config.setupdir)
+ elif self.config.skipsdist:
+ self.finishvenv(venv)
+ else:
+ self.installpkg(venv, sdist_path)
+ self.runtestenv(venv)
retcode = self._summary()
return retcode
- def runtestenv(self, venv, sdist_path, redirect=False):
+ def runtestenv(self, venv, redirect=False):
if not self.config.option.notest:
if venv.status:
return
@@ -408,6 +435,8 @@
self.report.keyvalue("toxworkdir: ", self.config.toxworkdir)
self.report.keyvalue("setupdir: ", self.config.setupdir)
self.report.keyvalue("distshare: ", self.config.distshare)
+ self.report.keyvalue("skipsdist: ", self.config.skipsdist)
+ self.report.keyvalue("usedevelop: ", self.config.usedevelop)
self.report.tw.line()
for envconfig in self.config.envconfigs.values():
self.report.line("[testenv:%s]" % envconfig.envname, bold=True)
diff -r 2567d6b26c8995df6cacee337d90f34418057293 -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -90,6 +90,8 @@
help="skip invoking test commands.")
parser.add_argument("--sdistonly", action="store_true", dest="sdistonly",
help="only perform the sdist packaging activity.")
+ parser.add_argument("--develop", action="store_true", dest="develop",
+ help="install package in the venv using setup.py develop")
parser.add_argument("--installpkg", action="store", default=None,
help="use specified package for installation into venv")
parser.add_argument('-i', action="append",
@@ -194,6 +196,10 @@
homedir=config.homedir)
config.toxworkdir = reader.getpath(toxsection, "toxworkdir",
"{toxinidir}/.tox")
+ config.usedevelop = reader.getbool(toxsection, "usedevelop", False)
+ config.skipsdist = reader.getbool(toxsection, "skipsdist",
+ config.usedevelop
+ or config.option.develop)
config.minversion = reader.getdefault(toxsection, "minversion", None)
# determine indexserver dictionary
diff -r 2567d6b26c8995df6cacee337d90f34418057293 -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -197,11 +197,36 @@
self._pcall(args, venv=False, action=action, cwd=basepath)
self.just_created = True
+ def finish(self):
+ self._getliveconfig().writeconfig(self.path_config)
+
+ def _needs_reinstall(self, setupdir, action):
+ setup_py = setupdir.join('setup.py')
+ setup_cfg = setupdir.join('setup.cfg')
+ args = [str(self.getconfigexecutable()), str(setup_py), '--name']
+ output = action.popen(args, cwd=setupdir, redirect=False,
+ returnout=True)
+ name = output.strip().decode('utf-8')
+ egg_info = setupdir.join('.'.join((name, 'egg-info')))
+ for conf_file in (setup_py, setup_cfg):
+ if (not egg_info.check() or (conf_file.check()
+ and conf_file.mtime() > egg_info.mtime())):
+ return True
+ return False
+
+ def developpkg(self, setupdir, action):
+ assert action is not None
+ self.finish()
+ if not self._needs_reinstall(setupdir, action):
+ return
+ extraopts = ['--no-deps']
+ self._install(['-e', setupdir], extraopts=extraopts, action=action)
+
def installpkg(self, sdistpath, action):
assert action is not None
if getattr(self, 'just_created', False):
action.setactivity("inst", sdistpath)
- self._getliveconfig().writeconfig(self.path_config)
+ self.finish()
extraopts = []
else:
action.setactivity("inst-nodeps", sdistpath)
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 Tue Jul 16 17:10:48 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Tue, 16 Jul 2013 15:10:48 -0000
Subject: [Pytest-commit] commit/tox: 2 new changesets
Message-ID: <20130716151048.30963.19309@app03.ash-private.bitbucket.org>
2 new commits in tox:
https://bitbucket.org/hpk42/tox/commits/f37eb1b0e101/
Changeset: f37eb1b0e101
User: hpk42
Date: 2013-07-16 17:06:22
Summary: add new config options ``usedevelop`` and ``skipsdist`` as well as a
command line option ``--develop`` to install the package-under-test in develop mode.
thanks Monty Taylor.
Affected #: 5 files
diff -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 -r f37eb1b0e101edf09eebe9ca4eb5b83de4e9edfe CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,10 @@
1.5.1.dev
-----------------
+- add new config options ``usedevelop`` and ``skipsdist`` as well as a
+ command line option ``--develop`` to install the package-under-test in develop mode.
+ thanks Monty Tailor for the PR.
+
- always unset PYTHONDONTWRITEBYTE because newer setuptools doesn't like it
1.5.0
diff -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 -r f37eb1b0e101edf09eebe9ca4eb5b83de4e9edfe CONTRIBUTORS
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -10,3 +10,4 @@
Ronny Pfannschmidt
Lukasz Balcerzak
Philip Thiem
+Monty Taylor
diff -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 -r f37eb1b0e101edf09eebe9ca4eb5b83de4e9edfe setup.py
--- a/setup.py
+++ b/setup.py
@@ -26,7 +26,7 @@
description='virtualenv-based automation of test activities',
long_description=open("README.rst").read(),
url='http://tox.testrun.org/',
- version='1.5.1.dev1',
+ version='1.5.1.dev2',
license='http://opensource.org/licenses/MIT',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
author='holger krekel',
diff -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 -r f37eb1b0e101edf09eebe9ca4eb5b83de4e9edfe tox/__init__.py
--- a/tox/__init__.py
+++ b/tox/__init__.py
@@ -1,5 +1,5 @@
#
-__version__ = '1.5.1.dev1'
+__version__ = '1.5.1.dev2'
class exception:
class Error(Exception):
diff -r bfc4a27950dce50e8d49ede674ca73fdaecdf981 -r f37eb1b0e101edf09eebe9ca4eb5b83de4e9edfe toxbootstrap.py
--- a/toxbootstrap.py
+++ b/toxbootstrap.py
@@ -58,7 +58,7 @@
"""
-__version__ = '1.5.1.dev1'
+__version__ = '1.5.1.dev2'
import sys
import os
https://bitbucket.org/hpk42/tox/commits/8c7e68bd1c8e/
Changeset: 8c7e68bd1c8e
User: hpk42
Date: 2013-07-16 17:10:42
Summary: remove obsolete tests - i think Lukasz left this in erranously
Affected #: 1 file
diff -r f37eb1b0e101edf09eebe9ca4eb5b83de4e9edfe -r 8c7e68bd1c8e5e29101ea9dc54c0525476295a0c tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -60,20 +60,6 @@
envconfig = config.envconfigs['devenv']
assert envconfig.envdir == config.toxworkdir.join('foobar')
- def test_package_flag(self, tmpdir, newconfig):
- config = newconfig([], """
- [testenv:py27]
- """)
- envconfig = config.envconfigs['py27']
- assert envconfig.package == True
-
- config = newconfig([], """
- [testenv:py27]
- package = False
- """)
- envconfig = config.envconfigs['py27']
- assert envconfig.package == False
-
class TestConfigPackage:
def test_defaults(self, tmpdir, newconfig):
config = newconfig([], "")
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 Jul 17 09:55:15 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 17 Jul 2013 07:55:15 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: paint last line red if
"failures" or "errors" occured, attribute theuni
Message-ID: <20130717075515.6547.3818@app05.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/6b10ac6e0a44/
Changeset: 6b10ac6e0a44
User: hpk42
Date: 2013-07-17 09:31:55
Summary: paint last line red if "failures" or "errors" occured, attribute theuni
Affected #: 3 files
diff -r 6e5fd004c38df785e08fdad5d7eaf3095b8fbd0f -r 6b10ac6e0a44682ce1ba97e06eb61b1c90774938 AUTHORS
--- a/AUTHORS
+++ b/AUTHORS
@@ -33,4 +33,4 @@
Andreas Zeidler
Brian Okken
Katarzyna Jachim
-
+Christian Theunert
diff -r 6e5fd004c38df785e08fdad5d7eaf3095b8fbd0f -r 6b10ac6e0a44682ce1ba97e06eb61b1c90774938 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
Changes between 2.3.5 and 2.4.DEV
-----------------------------------
+- 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.
diff -r 6e5fd004c38df785e08fdad5d7eaf3095b8fbd0f -r 6b10ac6e0a44682ce1ba97e06eb61b1c90774938 _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -457,7 +457,7 @@
msg = "%s in %.2f seconds" % (line, session_duration)
if self.verbosity >= 0:
markup = dict(bold=True)
- if 'failed' in self.stats:
+ if 'failed' in self.stats or 'error' in self.stats:
markup['red'] = True
else:
markup['green'] = True
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 Jul 17 10:29:18 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 17 Jul 2013 08:29:18 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: SO-17664702: call fixture
finalizers even if the fixture function
Message-ID: <20130717082918.13491.50727@app01.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/39a686b8775f/
Changeset: 39a686b8775f
User: hpk42
Date: 2013-07-17 10:29:11
Summary: SO-17664702: call fixture finalizers even if the fixture function
partially failed (finalizers would not always be called before)
Affected #: 5 files
diff -r 6b10ac6e0a44682ce1ba97e06eb61b1c90774938 -r 39a686b8775f100730751756e1b638e7a305e182 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
Changes between 2.3.5 and 2.4.DEV
-----------------------------------
+- 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.
diff -r 6b10ac6e0a44682ce1ba97e06eb61b1c90774938 -r 39a686b8775f100730751756e1b638e7a305e182 _pytest/__init__.py
--- a/_pytest/__init__.py
+++ b/_pytest/__init__.py
@@ -1,2 +1,2 @@
#
-__version__ = '2.4.0.dev6'
+__version__ = '2.4.0.dev7'
diff -r 6b10ac6e0a44682ce1ba97e06eb61b1c90774938 -r 39a686b8775f100730751756e1b638e7a305e182 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -1290,15 +1290,21 @@
# route request.addfinalizer to fixturedef
mp.setattr(self, "addfinalizer", fixturedef.addfinalizer)
- # perform the fixture call
- val = fixturedef.execute(request=self)
+ try:
+ # perform the fixture call
+ val = fixturedef.execute(request=self)
+ finally:
+ # if the fixture function failed it might still have
+ # registered finalizers so we can register
- # prepare finalization according to scope
- # (XXX analyse exact finalizing mechanics / cleanup)
- self.session._setupstate.addfinalizer(fixturedef.finish, self.node)
- self._fixturemanager.addargfinalizer(fixturedef.finish, argname)
- for subargname in fixturedef.argnames: # XXX all deps?
- self._fixturemanager.addargfinalizer(fixturedef.finish, subargname)
+ # prepare finalization according to scope
+ # (XXX analyse exact finalizing mechanics / cleanup)
+ self.session._setupstate.addfinalizer(fixturedef.finish,
+ self.node)
+ self._fixturemanager.addargfinalizer(fixturedef.finish, argname)
+ for subargname in fixturedef.argnames: # XXX all deps?
+ self._fixturemanager.addargfinalizer(fixturedef.finish,
+ subargname)
mp.undo()
return val
diff -r 6b10ac6e0a44682ce1ba97e06eb61b1c90774938 -r 39a686b8775f100730751756e1b638e7a305e182 setup.py
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,7 @@
name='pytest',
description='py.test: simple powerful testing with Python',
long_description = long_description,
- version='2.4.0.dev6',
+ version='2.4.0.dev7',
url='http://pytest.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
diff -r 6b10ac6e0a44682ce1ba97e06eb61b1c90774938 -r 39a686b8775f100730751756e1b638e7a305e182 testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -309,6 +309,39 @@
print(ss.stack)
assert teardownlist == [1]
+ def test_request_addfinalizer_failing_setup(self, testdir):
+ testdir.makepyfile("""
+ import pytest
+ l = [1]
+ @pytest.fixture
+ def myfix(request):
+ request.addfinalizer(l.pop)
+ assert 0
+ def test_fix(myfix):
+ pass
+ def test_finalizer_ran():
+ assert not l
+ """)
+ reprec = testdir.inline_run("-s")
+ reprec.assertoutcome(failed=1, passed=1)
+
+ def test_request_addfinalizer_failing_setup_module(self, testdir):
+ testdir.makepyfile("""
+ import pytest
+ l = [1, 2]
+ @pytest.fixture(scope="module")
+ def myfix(request):
+ request.addfinalizer(l.pop)
+ request.addfinalizer(l.pop)
+ assert 0
+ def test_fix(myfix):
+ pass
+ """)
+ reprec = testdir.inline_run("-s")
+ mod = reprec.getcalls("pytest_runtest_setup")[0].item.module
+ assert not mod.l
+
+
def test_request_addfinalizer_partial_setup_failure(self, testdir):
p = testdir.makepyfile("""
l = []
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 Jul 17 10:38:04 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 17 Jul 2013 08:38:04 -0000
Subject: [Pytest-commit] commit/tox: 5 new changesets
Message-ID: <20130717083804.14457.56342@app13.ash-private.bitbucket.org>
5 new commits in tox:
https://bitbucket.org/hpk42/tox/commits/f9f760fb37a9/
Changeset: f9f760fb37a9
User: mordred
Date: 2013-07-16 17:21:11
Summary: Expand --develop help text to be more correct
The --develop option actually triggers pip install -e . instead of
calling setup.py develop directly. Be clear about that.
Affected #: 1 file
diff -r 8c7e68bd1c8e5e29101ea9dc54c0525476295a0c -r f9f760fb37a95f36f934cb010a5a8cacb65f1657 tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -91,7 +91,8 @@
parser.add_argument("--sdistonly", action="store_true", dest="sdistonly",
help="only perform the sdist packaging activity.")
parser.add_argument("--develop", action="store_true", dest="develop",
- help="install package in the venv using setup.py develop")
+ help="install package in the venv using setup.py develop using "
+ "'pip -e .'")
parser.add_argument("--installpkg", action="store", default=None,
help="use specified package for installation into venv")
parser.add_argument('-i', action="append",
https://bitbucket.org/hpk42/tox/commits/139084074f08/
Changeset: 139084074f08
User: mordred
Date: 2013-07-16 17:25:24
Summary: Don't run --no-deps on intial install
Copy the logic from installpkg more completely.
Affected #: 1 file
diff -r f9f760fb37a95f36f934cb010a5a8cacb65f1657 -r 139084074f081f014758e4549209f8ac5c8a82a6 tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -216,10 +216,15 @@
def developpkg(self, setupdir, action):
assert action is not None
- self.finish()
+ if getattr(self, 'just_created', False):
+ action.setactivity("inst", sdistpath)
+ self.finish()
+ extraopts = []
+ else:
+ action.setactivity("inst-nodeps", sdistpath)
+ extraopts = ['--no-deps']
if not self._needs_reinstall(setupdir, action):
return
- extraopts = ['--no-deps']
self._install(['-e', setupdir], extraopts=extraopts, action=action)
def installpkg(self, sdistpath, action):
https://bitbucket.org/hpk42/tox/commits/1a80bac8f67d/
Changeset: 1a80bac8f67d
User: mordred
Date: 2013-07-16 17:39:42
Summary: Report better on what we're doing
develop mode should emit actions telling us what it's doing.
Affected #: 2 files
diff -r 139084074f081f014758e4549209f8ac5c8a82a6 -r 1a80bac8f67d32948751b20ee66f98ff03ec29ed tests/test_z_cmdline.py
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -362,7 +362,16 @@
def test_develop(initproj, cmd):
initproj("example123", filedefs={'tox.ini': """
"""})
- result = cmd.run("tox", "-v", "--develop")
+ result = cmd.run("tox", "-vv", "--develop")
+ assert not result.ret
+ assert "sdist-make" not in result.stdout.str()
+
+def test_usedevelop(initproj, cmd):
+ initproj("example123", filedefs={'tox.ini': """
+ [tox]
+ usedevelop=True
+ """})
+ result = cmd.run("tox", "-vv")
assert not result.ret
assert "sdist-make" not in result.stdout.str()
diff -r 139084074f081f014758e4549209f8ac5c8a82a6 -r 1a80bac8f67d32948751b20ee66f98ff03ec29ed tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -217,14 +217,15 @@
def developpkg(self, setupdir, action):
assert action is not None
if getattr(self, 'just_created', False):
- action.setactivity("inst", sdistpath)
+ action.setactivity("develop-inst", setupdir)
self.finish()
extraopts = []
else:
- action.setactivity("inst-nodeps", sdistpath)
+ if not self._needs_reinstall(setupdir, action):
+ action.setactivity("develop-inst-noop", setupdir)
+ return
+ action.setactivity("develop-inst-nodeps", setupdir)
extraopts = ['--no-deps']
- if not self._needs_reinstall(setupdir, action):
- return
self._install(['-e', setupdir], extraopts=extraopts, action=action)
def installpkg(self, sdistpath, action):
https://bitbucket.org/hpk42/tox/commits/44e60897da2b/
Changeset: 44e60897da2b
User: mordred
Date: 2013-07-16 17:57:41
Summary: Add develop to the configs that trigger recreate
Affected #: 4 files
diff -r 1a80bac8f67d32948751b20ee66f98ff03ec29ed -r 44e60897da2beb01adb940ef972bc58d7c076e03 tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -370,6 +370,7 @@
assert envconfig.changedir == config.setupdir
assert envconfig.distribute == False
assert envconfig.sitepackages == False
+ assert envconfig.develop == False
assert envconfig.envlogdir == envconfig.envdir.join("log")
assert envconfig.setenv is None
diff -r 1a80bac8f67d32948751b20ee66f98ff03ec29ed -r 44e60897da2beb01adb940ef972bc58d7c076e03 tests/test_venv.py
--- a/tests/test_venv.py
+++ b/tests/test_venv.py
@@ -473,6 +473,18 @@
venv.update()
mocksession.report.expect("verbosity0", "*recreate*")
+ def test_develop_recreation(self, newconfig, mocksession):
+ config = newconfig([], "")
+ envconfig = config.envconfigs['python']
+ venv = VirtualEnv(envconfig, session=mocksession)
+ venv.update()
+ cconfig = venv._getliveconfig()
+ cconfig.develop = True
+ cconfig.writeconfig(venv.path_config)
+ mocksession._clearmocks()
+ venv.update()
+ mocksession.report.expect("verbosity0", "*recreate*")
+
class TestVenvTest:
def test_patchPATH(self, newmocksession, monkeypatch):
diff -r 1a80bac8f67d32948751b20ee66f98ff03ec29ed -r 44e60897da2beb01adb940ef972bc58d7c076e03 tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -262,6 +262,7 @@
vc.config = config
reader = IniReader(self._cfg, fallbacksections=["testenv"])
reader.addsubstitions(**subs)
+ vc.develop = config.usedevelop or config.option.develop
vc.envdir = reader.getpath(section, "envdir", "{toxworkdir}/%s" % name)
vc.args_are_paths = reader.getbool(section, "args_are_paths", True)
if reader.getdefault(section, "python", None):
diff -r 1a80bac8f67d32948751b20ee66f98ff03ec29ed -r 44e60897da2beb01adb940ef972bc58d7c076e03 tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -5,18 +5,20 @@
from tox._config import DepConfig
class CreationConfig:
- def __init__(self, md5, python, version, distribute, sitepackages, deps):
+ def __init__(self, md5, python, version, distribute, sitepackages,
+ develop, deps):
self.md5 = md5
self.python = python
self.version = version
self.distribute = distribute
self.sitepackages = sitepackages
+ self.develop = develop
self.deps = deps
def writeconfig(self, path):
lines = ["%s %s" % (self.md5, self.python)]
- lines.append("%s %d %d" % (self.version, self.distribute,
- self.sitepackages))
+ lines.append("%s %d %d %d" % (self.version, self.distribute,
+ self.sitepackages, self.develop))
for dep in self.deps:
lines.append("%s %s" % dep)
path.ensure()
@@ -28,15 +30,17 @@
lines = path.readlines(cr=0)
value = lines.pop(0).split(None, 1)
md5, python = value
- version, distribute, sitepackages = lines.pop(0).split(None, 2)
+ version, distribute, sitepackages, develop = lines.pop(0).split(
+ None, 3)
distribute = bool(int(distribute))
sitepackages = bool(int(sitepackages))
+ develop = bool(int(develop))
deps = []
for line in lines:
md5, depstring = line.split(None, 1)
deps.append((md5, depstring))
return CreationConfig(md5, python, version,
- distribute, sitepackages, deps)
+ distribute, sitepackages, develop, deps)
except KeyboardInterrupt:
raise
except:
@@ -48,6 +52,7 @@
and self.version == other.version
and self.distribute == other.distribute
and self.sitepackages == other.sitepackages
+ and self.develop == other.develop
and self.deps == other.deps)
class VirtualEnv(object):
@@ -144,13 +149,14 @@
version = tox.__version__
distribute = self.envconfig.distribute
sitepackages = self.envconfig.sitepackages
+ develop = self.envconfig.develop
deps = []
for dep in self._getresolvedeps():
raw_dep = dep.name
md5 = getdigest(raw_dep)
deps.append((md5, raw_dep))
return CreationConfig(md5, python, version,
- distribute, sitepackages, deps)
+ distribute, sitepackages, develop, deps)
def _getresolvedeps(self):
l = []
https://bitbucket.org/hpk42/tox/commits/fb612de381a7/
Changeset: fb612de381a7
User: mordred
Date: 2013-07-16 18:00:05
Summary: Use the python from the venv for setup.py --name
Affected #: 1 file
diff -r 44e60897da2beb01adb940ef972bc58d7c076e03 -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -209,7 +209,7 @@
def _needs_reinstall(self, setupdir, action):
setup_py = setupdir.join('setup.py')
setup_cfg = setupdir.join('setup.cfg')
- args = [str(self.getconfigexecutable()), str(setup_py), '--name']
+ args = [self.envconfig.envpython, str(setup_py), '--name']
output = action.popen(args, cwd=setupdir, redirect=False,
returnout=True)
name = output.strip().decode('utf-8')
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 Jul 24 11:16:25 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 24 Jul 2013 09:16:25 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: bump version
Message-ID: <20130724091625.26097.45630@app08.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/e753e3d414f7/
Changeset: e753e3d414f7
User: hpk42
Date: 2013-07-24 11:16:19
Summary: bump version
Affected #: 2 files
diff -r 39a686b8775f100730751756e1b638e7a305e182 -r e753e3d414f786143653d8b95145e2cf03bf746f _pytest/__init__.py
--- a/_pytest/__init__.py
+++ b/_pytest/__init__.py
@@ -1,2 +1,2 @@
#
-__version__ = '2.4.0.dev7'
+__version__ = '2.4.0.dev8'
diff -r 39a686b8775f100730751756e1b638e7a305e182 -r e753e3d414f786143653d8b95145e2cf03bf746f setup.py
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,7 @@
name='pytest',
description='py.test: simple powerful testing with Python',
long_description = long_description,
- version='2.4.0.dev7',
+ version='2.4.0.dev8',
url='http://pytest.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', '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 notifications at travis-ci.org Wed Jul 24 11:21:01 2013
From: notifications at travis-ci.org (Travis CI)
Date: Wed, 24 Jul 2013 09:21:01 +0000
Subject: [Pytest-commit] [Broken] hpk42/pytest#22 (master - d1dec1e)
Message-ID: <51ef9c7d79180_24fa51e2073e3@509c3f74-6484-4ebe-8685-094ed955e533.mail>
Build Update for hpk42/pytest
-------------------------------------
Build: #22
Status: Broken
Duration: 3 minutes and 48 seconds
Commit: d1dec1e (master)
Author: holger krekel
Message: bump version
View the changeset: https://github.com/hpk42/pytest/compare/b763c4879e3b...d1dec1e32cb1
View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/9425921
--
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 Jul 24 12:08:37 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 24 Jul 2013 10:08:37 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: stick to virtualenv<1.10 for
now because it breaks python2.5
Message-ID: <20130724100837.10702.91292@app24.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/ae8fcfe3d678/
Changeset: ae8fcfe3d678
User: hpk42
Date: 2013-07-24 12:08:20
Summary: stick to virtualenv<1.10 for now because it breaks python2.5
Affected #: 1 file
diff -r e753e3d414f786143653d8b95145e2cf03bf746f -r ae8fcfe3d6786e54f30bf3a680688ea66d73914e .travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
language: python
# command to install dependencies
-install: "pip install -e . detox"
+install: "pip install 'virtualenv<1.10' -e . detox"
# # command to run tests
script: detox --recreate
notifications:
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 Jul 24 12:15:02 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 24 Jul 2013 10:15:02 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: mention github and bitbucket
Message-ID: <20130724101502.24393.62807@app09.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/abfc7dc64ed4/
Changeset: abfc7dc64ed4
User: hpk42
Date: 2013-07-24 12:14:53
Summary: mention github and bitbucket
Affected #: 1 file
diff -r ae8fcfe3d6786e54f30bf3a680688ea66d73914e -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 README.rst
--- a/README.rst
+++ b/README.rst
@@ -35,4 +35,10 @@
http://bitbucket.org/hpk42/pytest/issues/
+and checkout repos at:
+
+ http://github.com/hpk42/pytest/ (mirror)
+ http://bitbucket.org/hpk42/pytest/
+
+
Copyright Holger Krekel and others, 2004-2013
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 Jul 24 14:46:04 2013
From: issues-reply at bitbucket.org (vmalloc)
Date: Wed, 24 Jul 2013 12:46:04 -0000
Subject: [Pytest-commit] Issue #106: Add option to use wheel when installing
packages (hpk42/tox)
Message-ID: <20130724124604.11751.478@app18.ash-private.bitbucket.org>
New issue 106: Add option to use wheel when installing packages
https://bitbucket.org/hpk42/tox/issue/106/add-option-to-use-wheel-when-installing
vmalloc:
The new pip 1.4 (and virtualenv 1.10) support the wheel package format, and can automatically cache downloaded and built packages in a custom location. This would be extremely useful for tox, as rerunning it multiple times will require no extra build time...
From commits-noreply at bitbucket.org Fri Jul 26 07:41:49 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Fri, 26 Jul 2013 05:41:49 -0000
Subject: [Pytest-commit] commit/pytest: 3 new changesets
Message-ID: <20130726054149.3261.3421@app05.ash-private.bitbucket.org>
3 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/a3f34a534d44/
Changeset: a3f34a534d44
Branch: argparse
User: Anthon van der Neut
Date: 2013-07-25 15:33:43
Summary: moving from optparse to argparse. Major difficulty is
that argparse does not have Option objects -> added class Argument
Needed explicit call of MyOptionParser.format_epilog as argparse
does not have that. The parse_arg epilog argument wraps the text,
which is not the same (could be handled with a special formatter).
- parser.parse() now returns single argument (with positional args in
.file_or_dir)
- "file_or_dir" made a class variable Config._file_or_dir and used in help and tests
- added code for argcomplete (because of which this all started!)
addoption:
- if option type is a string ('int' or 'string', this converted to
int resp. str
- if option type is 'count' this is changed to the type of choices[0]
testing:
- added tests for Argument
- test_mark.test_keyword_extra split as ['-k', '-mykeyword'] generates argparse
error test split in two and one marked as fail
- testing hints, multiline and more strickt (for if someone moves format_epilog
to epilog argument of parse_args without Formatter)
- test for destination derived from long option with internal dash
- renamed second test_parseopt.test_parse() to test_parse2 as it was
not tested at all (the first was tested.)
Affected #: 11 files
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 _pytest/capture.py
--- a/_pytest/capture.py
+++ b/_pytest/capture.py
@@ -6,7 +6,7 @@
def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption('--capture', action="store", default=None,
- metavar="method", type="choice", choices=['fd', 'sys', 'no'],
+ 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",
help="shortcut for --capture=no.")
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -80,16 +80,20 @@
for group in groups:
if group.options:
desc = group.description or group.name
- optgroup = py.std.optparse.OptionGroup(optparser, desc)
- optgroup.add_options(group.options)
- optparser.add_option_group(optgroup)
+ arggroup = optparser.add_argument_group(desc)
+ for option in group.options:
+ n = option.names()
+ a = option.attrs()
+ arggroup.add_argument(*n, **a)
+ optparser.add_argument(Config._file_or_dir, nargs='*')
+ try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args])
def parse_setoption(self, args, option):
- parsedoption, args = self.parse(args)
+ parsedoption = self.parse(args)
for name, value in parsedoption.__dict__.items():
setattr(option, name, value)
- return args
+ return getattr(parsedoption, Config._file_or_dir)
def addini(self, name, help, type=None, default=None):
""" register an ini-file option.
@@ -105,7 +109,133 @@
self._inidict[name] = (help, type, default)
self._ininames.append(name)
+def try_argcomplete(parser):
+ try:
+ import argcomplete
+ except ImportError:
+ pass
+ else:
+ argcomplete.autocomplete(parser)
+class ArgumentError(Exception):
+ """
+ Raised if an Argument instance is created with invalid or
+ inconsistent arguments.
+ """
+
+ def __init__(self, msg, option):
+ self.msg = msg
+ self.option_id = str(option)
+
+ def __str__(self):
+ if self.option_id:
+ return "option %s: %s" % (self.option_id, self.msg)
+ else:
+ return self.msg
+
+
+class Argument:
+ """class that mimics the necessary behaviour of py.std.optparse.Option """
+ _typ_map = {
+ 'int': int,
+ 'string': str,
+ }
+
+ def __init__(self, *names, **attrs):
+ """store parms in private vars for use in add_argument"""
+ self._attrs = attrs
+ self._short_opts = []
+ self._long_opts = []
+ self.dest = attrs.get('dest')
+ try:
+ typ = attrs['type']
+ except KeyError:
+ pass
+ else:
+ # this might raise a keyerror as well, don't want to catch that
+ if isinstance(typ, str):
+ if typ == 'choice':
+ # argparse expects a type here take it from
+ # the type of the first element
+ attrs['type'] = type(attrs['choices'][0])
+ else:
+ attrs['type'] = Argument._typ_map[typ]
+ # used in test_parseopt -> test_parse_defaultgetter
+ self.type = attrs['type']
+ else:
+ self.type = typ
+ try:
+ # attribute existence is tested in Config._processopt
+ self.default = attrs['default']
+ except KeyError:
+ pass
+ self._set_opt_strings(names)
+ if not self.dest:
+ if self._long_opts:
+ self.dest = self._long_opts[0][2:].replace('-', '_')
+ else:
+ try:
+ self.dest = self._short_opts[0][1:]
+ except IndexError:
+ raise ArgumentError(
+ 'need a long or short option', self)
+
+ def names(self):
+ return self._short_opts + self._long_opts
+
+ def attrs(self):
+ # update any attributes set by processopt
+ attrs = 'default dest'.split()
+ if self.dest:
+ attrs.append(self.dest)
+ for attr in attrs:
+ try:
+ self._attrs[attr] = getattr(self, attr)
+ except AttributeError:
+ pass
+ return self._attrs
+
+ def _set_opt_strings(self, opts):
+ """directly from optparse
+
+ might not be necessary as this is passed to argparse later on"""
+ for opt in opts:
+ if len(opt) < 2:
+ raise ArgumentError(
+ "invalid option string %r: "
+ "must be at least two characters long" % opt, self)
+ elif len(opt) == 2:
+ if not (opt[0] == "-" and opt[1] != "-"):
+ raise ArgumentError(
+ "invalid short option string %r: "
+ "must be of the form -x, (x any non-dash char)" % opt,
+ self)
+ self._short_opts.append(opt)
+ else:
+ if not (opt[0:2] == "--" and opt[2] != "-"):
+ raise ArgumentError(
+ "invalid long option string %r: "
+ "must start with --, followed by non-dash" % opt,
+ self)
+ self._long_opts.append(opt)
+
+ def __repr__(self):
+ retval = 'Argument('
+ if self._short_opts:
+ retval += '_short_opts: ' + repr(self._short_opts) + ', '
+ if self._long_opts:
+ retval += '_long_opts: ' + repr(self._long_opts) + ', '
+ retval += 'dest: ' + repr(self.dest) + ', '
+ if hasattr(self, 'type'):
+ retval += 'type: ' + repr(self.type) + ', '
+ if hasattr(self, 'default'):
+ retval += 'default: ' + repr(self.default) + ', '
+ if retval[-2:] == ', ': # always long enough to test ("Argument(" )
+ retval = retval[:-2]
+ retval += ')'
+ return retval
+
+
class OptionGroup:
def __init__(self, name, description="", parser=None):
self.name = name
@@ -115,11 +245,11 @@
def addoption(self, *optnames, **attrs):
""" add an option to this group. """
- option = py.std.optparse.Option(*optnames, **attrs)
+ option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=False)
def _addoption(self, *optnames, **attrs):
- option = py.std.optparse.Option(*optnames, **attrs)
+ option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=True)
def _addoption_instance(self, option, shortupper=False):
@@ -132,11 +262,11 @@
self.options.append(option)
-class MyOptionParser(py.std.optparse.OptionParser):
+class MyOptionParser(py.std.argparse.ArgumentParser):
def __init__(self, parser):
self._parser = parser
- py.std.optparse.OptionParser.__init__(self, usage=parser._usage,
- add_help_option=False)
+ py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage,
+ add_help=False)
def format_epilog(self, formatter):
hints = self._parser.hints
if hints:
@@ -263,12 +393,15 @@
class Config(object):
""" access to configuration values, pluginmanager and plugin hooks. """
+ _file_or_dir = 'file_or_dir'
+
def __init__(self, pluginmanager=None):
#: access to command line option as attributes.
#: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead
self.option = CmdOptions()
+ _a = self._file_or_dir
self._parser = Parser(
- usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
+ usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a),
processopt=self._processopt,
)
#: a pluginmanager instance
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 _pytest/helpconfig.py
--- a/_pytest/helpconfig.py
+++ b/_pytest/helpconfig.py
@@ -62,6 +62,7 @@
def showhelp(config):
tw = py.io.TerminalWriter()
tw.write(config._parser.optparser.format_help())
+ tw.write(config._parser.optparser.format_epilog(None))
tw.line()
tw.line()
#tw.sep( "=", "config file settings")
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 _pytest/hookspec.py
--- a/_pytest/hookspec.py
+++ b/_pytest/hookspec.py
@@ -23,7 +23,7 @@
"""modify command line arguments before option parsing. """
def pytest_addoption(parser):
- """register optparse-style options and ini-style config values.
+ """register argparse-style options and ini-style config values.
This function must be implemented in a :ref:`plugin ` and is
called once at the beginning of a test run.
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 _pytest/main.py
--- a/_pytest/main.py
+++ b/_pytest/main.py
@@ -35,7 +35,7 @@
dest="exitfirst",
help="exit instantly on first error or failed test."),
group._addoption('--maxfail', metavar="num",
- action="store", type="int", dest="maxfail", default=0,
+ action="store", type=int, dest="maxfail", default=0,
help="exit after first num failures or errors.")
group._addoption('--strict', action="store_true",
help="run pytest in strict mode, warnings become errors.")
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 _pytest/pastebin.py
--- a/_pytest/pastebin.py
+++ b/_pytest/pastebin.py
@@ -10,7 +10,7 @@
group = parser.getgroup("terminal reporting")
group._addoption('--pastebin', metavar="mode",
action='store', dest="pastebin", default=None,
- type="choice", choices=['failed', 'all'],
+ choices=['failed', 'all'],
help="send failed|all info to bpaste.net pastebin service.")
def pytest_configure(__multicall__, config):
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 _pytest/runner.py
--- a/_pytest/runner.py
+++ b/_pytest/runner.py
@@ -18,7 +18,7 @@
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "reporting", after="general")
group.addoption('--durations',
- action="store", type="int", default=None, metavar="N",
+ action="store", type=int, default=None, metavar="N",
help="show N slowest setup/test durations (N=0 for all)."),
def pytest_terminal_summary(terminalreporter):
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -25,7 +25,7 @@
help="(deprecated, use -r)")
group._addoption('--tb', metavar="style",
action="store", dest="tbstyle", default='long',
- type="choice", choices=['long', 'short', 'no', 'line', 'native'],
+ choices=['long', 'short', 'no', 'line', 'native'],
help="traceback print mode (long/short/line/native/no).")
group._addoption('--fulltrace',
action="store_true", dest="fulltrace", default=False,
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 pytest.py
--- a/pytest.py
+++ b/pytest.py
@@ -1,3 +1,4 @@
+# PYTHON_ARGCOMPLETE_OK
"""
pytest: unit and functional testing with Python.
"""
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 testing/test_mark.py
--- a/testing/test_mark.py
+++ b/testing/test_mark.py
@@ -451,12 +451,22 @@
assert 0
test_one.mykeyword = True
""")
+ reprec = testdir.inline_run("-k", "mykeyword", p)
+ passed, skipped, failed = reprec.countoutcomes()
+ assert failed == 1
+
+ @pytest.mark.xfail
+ def test_keyword_extra_dash(self, testdir):
+ p = testdir.makepyfile("""
+ def test_one():
+ assert 0
+ test_one.mykeyword = True
+ """)
+ # with argparse the argument to an option cannot
+ # start with '-'
reprec = testdir.inline_run("-k", "-mykeyword", p)
passed, skipped, failed = reprec.countoutcomes()
assert passed + skipped + failed == 0
- reprec = testdir.inline_run("-k", "mykeyword", p)
- passed, skipped, failed = reprec.countoutcomes()
- assert failed == 1
def test_no_magic_values(self, testdir):
"""Make sure the tests do not match on magic values,
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r a3f34a534d44feee1c77f5122402c761259a11d9 testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -7,8 +7,44 @@
parser = parseopt.Parser(usage="xyz")
pytest.raises(SystemExit, 'parser.parse(["-h"])')
out, err = capsys.readouterr()
- assert err.find("no such option") != -1
+ assert err.find("error: unrecognized arguments") != -1
+ def test_argument(self):
+ with pytest.raises(parseopt.ArgumentError):
+ # need a short or long option
+ argument = parseopt.Argument()
+ argument = parseopt.Argument('-t')
+ assert argument._short_opts == ['-t']
+ assert argument._long_opts == []
+ assert argument.dest == 't'
+ argument = parseopt.Argument('-t', '--test')
+ assert argument._short_opts == ['-t']
+ assert argument._long_opts == ['--test']
+ assert argument.dest == 'test'
+ argument = parseopt.Argument('-t', '--test', dest='abc')
+ assert argument.dest == 'abc'
+
+ def test_argument_type(self):
+ argument = parseopt.Argument('-t', dest='abc', type='int')
+ assert argument.type is int
+ argument = parseopt.Argument('-t', dest='abc', type='string')
+ assert argument.type is str
+ argument = parseopt.Argument('-t', dest='abc', type=float)
+ assert argument.type is float
+ with pytest.raises(KeyError):
+ argument = parseopt.Argument('-t', dest='abc', type='choice')
+ argument = parseopt.Argument('-t', dest='abc', type='choice',
+ choices=['red', 'blue'])
+ assert argument.type is str
+
+ def test_argument_processopt(self):
+ argument = parseopt.Argument('-t', type=int)
+ argument.default = 42
+ argument.dest = 'abc'
+ res = argument.attrs()
+ assert res['default'] == 42
+ assert res['dest'] == 'abc'
+
def test_group_add_and_get(self):
parser = parseopt.Parser()
group = parser.getgroup("hello", description="desc")
@@ -36,7 +72,7 @@
group = parseopt.OptionGroup("hello")
group.addoption("--option1", action="store_true")
assert len(group.options) == 1
- assert isinstance(group.options[0], py.std.optparse.Option)
+ assert isinstance(group.options[0], parseopt.Argument)
def test_group_shortopt_lowercase(self):
parser = parseopt.Parser()
@@ -58,19 +94,19 @@
def test_parse(self):
parser = parseopt.Parser()
parser.addoption("--hello", dest="hello", action="store")
- option, args = parser.parse(['--hello', 'world'])
- assert option.hello == "world"
- assert not args
+ args = parser.parse(['--hello', 'world'])
+ assert args.hello == "world"
+ assert not getattr(args, parseopt.Config._file_or_dir)
- def test_parse(self):
+ def test_parse2(self):
parser = parseopt.Parser()
- option, args = parser.parse([py.path.local()])
- assert args[0] == py.path.local()
+ args = parser.parse([py.path.local()])
+ assert getattr(args, parseopt.Config._file_or_dir)[0] == py.path.local()
def test_parse_will_set_default(self):
parser = parseopt.Parser()
parser.addoption("--hello", dest="hello", default="x", action="store")
- option, args = parser.parse([])
+ option = parser.parse([])
assert option.hello == "x"
del option.hello
args = parser.parse_setoption([], option)
@@ -87,28 +123,37 @@
assert option.world == 42
assert not args
+ def test_parse_special_destination(self):
+ parser = parseopt.Parser()
+ x = parser.addoption("--ultimate-answer", type=int)
+ args = parser.parse(['--ultimate-answer', '42'])
+ assert args.ultimate_answer == 42
+
def test_parse_defaultgetter(self):
def defaultget(option):
- if option.type == "int":
+ if not hasattr(option, 'type'):
+ return
+ if option.type is int:
option.default = 42
- elif option.type == "string":
+ elif option.type is str:
option.default = "world"
parser = parseopt.Parser(processopt=defaultget)
parser.addoption("--this", dest="this", type="int", action="store")
parser.addoption("--hello", dest="hello", type="string", action="store")
parser.addoption("--no", dest="no", action="store_true")
- option, args = parser.parse([])
+ option = parser.parse([])
assert option.hello == "world"
assert option.this == 42
-
+ assert option.no is False
@pytest.mark.skipif("sys.version_info < (2,5)")
def test_addoption_parser_epilog(testdir):
testdir.makeconftest("""
def pytest_addoption(parser):
parser.hints.append("hello world")
+ parser.hints.append("from me too")
""")
result = testdir.runpytest('--help')
#assert result.ret != 0
- result.stdout.fnmatch_lines(["*hint: hello world*"])
+ result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"])
https://bitbucket.org/hpk42/pytest/commits/8379d69dcb3f/
Changeset: 8379d69dcb3f
Branch: argparse
User: Anthon van der Neut
Date: 2013-07-25 17:26:48
Summary: auto change %default -> %(default)s in help parameter string (on retrieval)
added code for warnings on optparse arguments (type, help),
which can be easily switched on with TYPE_WARN = True in config.py
installed and tested ( py.test --help )
pytest-quickcheck-0.7
pytest-gae-0.2.2
pytest-growl-0.1
pytest-bdd-0.4.7
pytest-bdd-splinter-0.4.4
pytest-cache-1.0
pytest-capturelog-0.7
pytest-codecheckers-0.2
pytest-contextfixture-0.1.1
pytest-cov-1.6
pytest-flakes-0.1
pytest-incremental-0.3.0
pytest-xdist-1.8
pytest-localserver-0.1.5
pytest-monkeyplus-1.1.0
pytest-oerp-0.2.0
pytest-pep8-1.0.4
pytest-pydev-0.1
pytest-rage-0.1
pytest-runfailed-0.3
pytest-timeout-0.3
pytest-xprocess-0.7
pytest-browsermob-proxy-0.1
pytest-mozwebqa-1.1.1
pytest-random-0.02
pytest-rerunfailures-0.03
pytest-zap-0.1
pytest-blockage-0.1
pytest-django-2.3.0
pytest-figleaf-1.0
pytest-greendots-0.1
pytest-instafail-0.1.0
pytest-konira-0.2
pytest-marker-bugzilla-0.06
pytest-marks-0.4
pytest-poo-0.2
pytest-twisted-1.4
pytest-yamlwsgi-0.6
Affected #: 1 file
diff -r a3f34a534d44feee1c77f5122402c761259a11d9 -r 8379d69dcb3fbb3349daf1ae0a6d5441f8289a18 _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -5,6 +5,12 @@
from _pytest.core import PluginManager
import pytest
+# enable after some grace period for plugin writers
+TYPE_WARN = False
+if TYPE_WARN:
+ import warnings
+
+
def pytest_cmdline_parse(pluginmanager, args):
config = Config(pluginmanager)
config.parse(args)
@@ -147,6 +153,17 @@
self._short_opts = []
self._long_opts = []
self.dest = attrs.get('dest')
+ if TYPE_WARN:
+ try:
+ help = attrs['help']
+ if '%default' in help:
+ warnings.warn(
+ 'py.test now uses argparse. "%default" should be'
+ ' changed to "%(default)s" ',
+ FutureWarning,
+ stacklevel=3)
+ except KeyError:
+ pass
try:
typ = attrs['type']
except KeyError:
@@ -155,10 +172,25 @@
# this might raise a keyerror as well, don't want to catch that
if isinstance(typ, str):
if typ == 'choice':
+ if TYPE_WARN:
+ warnings.warn(
+ 'type argument to addoption() is a string %r.'
+ ' For parsearg this is optional and when supplied '
+ ' should be a type.'
+ ' (options: %s)' % (typ, names),
+ FutureWarning,
+ stacklevel=3)
# argparse expects a type here take it from
# the type of the first element
attrs['type'] = type(attrs['choices'][0])
else:
+ if TYPE_WARN:
+ warnings.warn(
+ 'type argument to addoption() is a string %r.'
+ ' For parsearg this should be a type.'
+ ' (options: %s)' % (typ, names),
+ FutureWarning,
+ stacklevel=3)
attrs['type'] = Argument._typ_map[typ]
# used in test_parseopt -> test_parse_defaultgetter
self.type = attrs['type']
@@ -185,7 +217,7 @@
def attrs(self):
# update any attributes set by processopt
- attrs = 'default dest'.split()
+ attrs = 'default dest help'.split()
if self.dest:
attrs.append(self.dest)
for attr in attrs:
@@ -193,6 +225,11 @@
self._attrs[attr] = getattr(self, attr)
except AttributeError:
pass
+ if self._attrs.get('help'):
+ a = self._attrs['help']
+ a = a.replace('%default', '%(default)s')
+ #a = a.replace('%prog', '%(prog)s')
+ self._attrs['help'] = a
return self._attrs
def _set_opt_strings(self, opts):
https://bitbucket.org/hpk42/pytest/commits/4405d5fd6cae/
Changeset: 4405d5fd6cae
User: hpk42
Date: 2013-07-26 07:41:43
Summary: Merged in anthon_van_der_neut/pytest/argparse (pull request #46)
argparse / argcomplete
Affected #: 11 files
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec _pytest/capture.py
--- a/_pytest/capture.py
+++ b/_pytest/capture.py
@@ -6,7 +6,7 @@
def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption('--capture', action="store", default=None,
- metavar="method", type="choice", choices=['fd', 'sys', 'no'],
+ 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",
help="shortcut for --capture=no.")
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -5,6 +5,12 @@
from _pytest.core import PluginManager
import pytest
+# enable after some grace period for plugin writers
+TYPE_WARN = False
+if TYPE_WARN:
+ import warnings
+
+
def pytest_cmdline_parse(pluginmanager, args):
config = Config(pluginmanager)
config.parse(args)
@@ -80,16 +86,20 @@
for group in groups:
if group.options:
desc = group.description or group.name
- optgroup = py.std.optparse.OptionGroup(optparser, desc)
- optgroup.add_options(group.options)
- optparser.add_option_group(optgroup)
+ arggroup = optparser.add_argument_group(desc)
+ for option in group.options:
+ n = option.names()
+ a = option.attrs()
+ arggroup.add_argument(*n, **a)
+ optparser.add_argument(Config._file_or_dir, nargs='*')
+ try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args])
def parse_setoption(self, args, option):
- parsedoption, args = self.parse(args)
+ parsedoption = self.parse(args)
for name, value in parsedoption.__dict__.items():
setattr(option, name, value)
- return args
+ return getattr(parsedoption, Config._file_or_dir)
def addini(self, name, help, type=None, default=None):
""" register an ini-file option.
@@ -105,7 +115,164 @@
self._inidict[name] = (help, type, default)
self._ininames.append(name)
+def try_argcomplete(parser):
+ try:
+ import argcomplete
+ except ImportError:
+ pass
+ else:
+ argcomplete.autocomplete(parser)
+class ArgumentError(Exception):
+ """
+ Raised if an Argument instance is created with invalid or
+ inconsistent arguments.
+ """
+
+ def __init__(self, msg, option):
+ self.msg = msg
+ self.option_id = str(option)
+
+ def __str__(self):
+ if self.option_id:
+ return "option %s: %s" % (self.option_id, self.msg)
+ else:
+ return self.msg
+
+
+class Argument:
+ """class that mimics the necessary behaviour of py.std.optparse.Option """
+ _typ_map = {
+ 'int': int,
+ 'string': str,
+ }
+
+ def __init__(self, *names, **attrs):
+ """store parms in private vars for use in add_argument"""
+ self._attrs = attrs
+ self._short_opts = []
+ self._long_opts = []
+ self.dest = attrs.get('dest')
+ if TYPE_WARN:
+ try:
+ help = attrs['help']
+ if '%default' in help:
+ warnings.warn(
+ 'py.test now uses argparse. "%default" should be'
+ ' changed to "%(default)s" ',
+ FutureWarning,
+ stacklevel=3)
+ except KeyError:
+ pass
+ try:
+ typ = attrs['type']
+ except KeyError:
+ pass
+ else:
+ # this might raise a keyerror as well, don't want to catch that
+ if isinstance(typ, str):
+ if typ == 'choice':
+ if TYPE_WARN:
+ warnings.warn(
+ 'type argument to addoption() is a string %r.'
+ ' For parsearg this is optional and when supplied '
+ ' should be a type.'
+ ' (options: %s)' % (typ, names),
+ FutureWarning,
+ stacklevel=3)
+ # argparse expects a type here take it from
+ # the type of the first element
+ attrs['type'] = type(attrs['choices'][0])
+ else:
+ if TYPE_WARN:
+ warnings.warn(
+ 'type argument to addoption() is a string %r.'
+ ' For parsearg this should be a type.'
+ ' (options: %s)' % (typ, names),
+ FutureWarning,
+ stacklevel=3)
+ attrs['type'] = Argument._typ_map[typ]
+ # used in test_parseopt -> test_parse_defaultgetter
+ self.type = attrs['type']
+ else:
+ self.type = typ
+ try:
+ # attribute existence is tested in Config._processopt
+ self.default = attrs['default']
+ except KeyError:
+ pass
+ self._set_opt_strings(names)
+ if not self.dest:
+ if self._long_opts:
+ self.dest = self._long_opts[0][2:].replace('-', '_')
+ else:
+ try:
+ self.dest = self._short_opts[0][1:]
+ except IndexError:
+ raise ArgumentError(
+ 'need a long or short option', self)
+
+ def names(self):
+ return self._short_opts + self._long_opts
+
+ def attrs(self):
+ # update any attributes set by processopt
+ attrs = 'default dest help'.split()
+ if self.dest:
+ attrs.append(self.dest)
+ for attr in attrs:
+ try:
+ self._attrs[attr] = getattr(self, attr)
+ except AttributeError:
+ pass
+ if self._attrs.get('help'):
+ a = self._attrs['help']
+ a = a.replace('%default', '%(default)s')
+ #a = a.replace('%prog', '%(prog)s')
+ self._attrs['help'] = a
+ return self._attrs
+
+ def _set_opt_strings(self, opts):
+ """directly from optparse
+
+ might not be necessary as this is passed to argparse later on"""
+ for opt in opts:
+ if len(opt) < 2:
+ raise ArgumentError(
+ "invalid option string %r: "
+ "must be at least two characters long" % opt, self)
+ elif len(opt) == 2:
+ if not (opt[0] == "-" and opt[1] != "-"):
+ raise ArgumentError(
+ "invalid short option string %r: "
+ "must be of the form -x, (x any non-dash char)" % opt,
+ self)
+ self._short_opts.append(opt)
+ else:
+ if not (opt[0:2] == "--" and opt[2] != "-"):
+ raise ArgumentError(
+ "invalid long option string %r: "
+ "must start with --, followed by non-dash" % opt,
+ self)
+ self._long_opts.append(opt)
+
+ def __repr__(self):
+ retval = 'Argument('
+ if self._short_opts:
+ retval += '_short_opts: ' + repr(self._short_opts) + ', '
+ if self._long_opts:
+ retval += '_long_opts: ' + repr(self._long_opts) + ', '
+ retval += 'dest: ' + repr(self.dest) + ', '
+ if hasattr(self, 'type'):
+ retval += 'type: ' + repr(self.type) + ', '
+ if hasattr(self, 'default'):
+ retval += 'default: ' + repr(self.default) + ', '
+ if retval[-2:] == ', ': # always long enough to test ("Argument(" )
+ retval = retval[:-2]
+ retval += ')'
+ return retval
+
+
class OptionGroup:
def __init__(self, name, description="", parser=None):
self.name = name
@@ -115,11 +282,11 @@
def addoption(self, *optnames, **attrs):
""" add an option to this group. """
- option = py.std.optparse.Option(*optnames, **attrs)
+ option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=False)
def _addoption(self, *optnames, **attrs):
- option = py.std.optparse.Option(*optnames, **attrs)
+ option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=True)
def _addoption_instance(self, option, shortupper=False):
@@ -132,11 +299,11 @@
self.options.append(option)
-class MyOptionParser(py.std.optparse.OptionParser):
+class MyOptionParser(py.std.argparse.ArgumentParser):
def __init__(self, parser):
self._parser = parser
- py.std.optparse.OptionParser.__init__(self, usage=parser._usage,
- add_help_option=False)
+ py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage,
+ add_help=False)
def format_epilog(self, formatter):
hints = self._parser.hints
if hints:
@@ -263,12 +430,15 @@
class Config(object):
""" access to configuration values, pluginmanager and plugin hooks. """
+ _file_or_dir = 'file_or_dir'
+
def __init__(self, pluginmanager=None):
#: access to command line option as attributes.
#: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead
self.option = CmdOptions()
+ _a = self._file_or_dir
self._parser = Parser(
- usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
+ usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a),
processopt=self._processopt,
)
#: a pluginmanager instance
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec _pytest/helpconfig.py
--- a/_pytest/helpconfig.py
+++ b/_pytest/helpconfig.py
@@ -62,6 +62,7 @@
def showhelp(config):
tw = py.io.TerminalWriter()
tw.write(config._parser.optparser.format_help())
+ tw.write(config._parser.optparser.format_epilog(None))
tw.line()
tw.line()
#tw.sep( "=", "config file settings")
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec _pytest/hookspec.py
--- a/_pytest/hookspec.py
+++ b/_pytest/hookspec.py
@@ -23,7 +23,7 @@
"""modify command line arguments before option parsing. """
def pytest_addoption(parser):
- """register optparse-style options and ini-style config values.
+ """register argparse-style options and ini-style config values.
This function must be implemented in a :ref:`plugin ` and is
called once at the beginning of a test run.
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec _pytest/main.py
--- a/_pytest/main.py
+++ b/_pytest/main.py
@@ -35,7 +35,7 @@
dest="exitfirst",
help="exit instantly on first error or failed test."),
group._addoption('--maxfail', metavar="num",
- action="store", type="int", dest="maxfail", default=0,
+ action="store", type=int, dest="maxfail", default=0,
help="exit after first num failures or errors.")
group._addoption('--strict', action="store_true",
help="run pytest in strict mode, warnings become errors.")
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec _pytest/pastebin.py
--- a/_pytest/pastebin.py
+++ b/_pytest/pastebin.py
@@ -10,7 +10,7 @@
group = parser.getgroup("terminal reporting")
group._addoption('--pastebin', metavar="mode",
action='store', dest="pastebin", default=None,
- type="choice", choices=['failed', 'all'],
+ choices=['failed', 'all'],
help="send failed|all info to bpaste.net pastebin service.")
def pytest_configure(__multicall__, config):
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec _pytest/runner.py
--- a/_pytest/runner.py
+++ b/_pytest/runner.py
@@ -18,7 +18,7 @@
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "reporting", after="general")
group.addoption('--durations',
- action="store", type="int", default=None, metavar="N",
+ action="store", type=int, default=None, metavar="N",
help="show N slowest setup/test durations (N=0 for all)."),
def pytest_terminal_summary(terminalreporter):
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -25,7 +25,7 @@
help="(deprecated, use -r)")
group._addoption('--tb', metavar="style",
action="store", dest="tbstyle", default='long',
- type="choice", choices=['long', 'short', 'no', 'line', 'native'],
+ choices=['long', 'short', 'no', 'line', 'native'],
help="traceback print mode (long/short/line/native/no).")
group._addoption('--fulltrace',
action="store_true", dest="fulltrace", default=False,
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec pytest.py
--- a/pytest.py
+++ b/pytest.py
@@ -1,3 +1,4 @@
+# PYTHON_ARGCOMPLETE_OK
"""
pytest: unit and functional testing with Python.
"""
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec testing/test_mark.py
--- a/testing/test_mark.py
+++ b/testing/test_mark.py
@@ -451,12 +451,22 @@
assert 0
test_one.mykeyword = True
""")
+ reprec = testdir.inline_run("-k", "mykeyword", p)
+ passed, skipped, failed = reprec.countoutcomes()
+ assert failed == 1
+
+ @pytest.mark.xfail
+ def test_keyword_extra_dash(self, testdir):
+ p = testdir.makepyfile("""
+ def test_one():
+ assert 0
+ test_one.mykeyword = True
+ """)
+ # with argparse the argument to an option cannot
+ # start with '-'
reprec = testdir.inline_run("-k", "-mykeyword", p)
passed, skipped, failed = reprec.countoutcomes()
assert passed + skipped + failed == 0
- reprec = testdir.inline_run("-k", "mykeyword", p)
- passed, skipped, failed = reprec.countoutcomes()
- assert failed == 1
def test_no_magic_values(self, testdir):
"""Make sure the tests do not match on magic values,
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 4405d5fd6caec4072177911d9af4e1c57fe66cec testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -7,8 +7,44 @@
parser = parseopt.Parser(usage="xyz")
pytest.raises(SystemExit, 'parser.parse(["-h"])')
out, err = capsys.readouterr()
- assert err.find("no such option") != -1
+ assert err.find("error: unrecognized arguments") != -1
+ def test_argument(self):
+ with pytest.raises(parseopt.ArgumentError):
+ # need a short or long option
+ argument = parseopt.Argument()
+ argument = parseopt.Argument('-t')
+ assert argument._short_opts == ['-t']
+ assert argument._long_opts == []
+ assert argument.dest == 't'
+ argument = parseopt.Argument('-t', '--test')
+ assert argument._short_opts == ['-t']
+ assert argument._long_opts == ['--test']
+ assert argument.dest == 'test'
+ argument = parseopt.Argument('-t', '--test', dest='abc')
+ assert argument.dest == 'abc'
+
+ def test_argument_type(self):
+ argument = parseopt.Argument('-t', dest='abc', type='int')
+ assert argument.type is int
+ argument = parseopt.Argument('-t', dest='abc', type='string')
+ assert argument.type is str
+ argument = parseopt.Argument('-t', dest='abc', type=float)
+ assert argument.type is float
+ with pytest.raises(KeyError):
+ argument = parseopt.Argument('-t', dest='abc', type='choice')
+ argument = parseopt.Argument('-t', dest='abc', type='choice',
+ choices=['red', 'blue'])
+ assert argument.type is str
+
+ def test_argument_processopt(self):
+ argument = parseopt.Argument('-t', type=int)
+ argument.default = 42
+ argument.dest = 'abc'
+ res = argument.attrs()
+ assert res['default'] == 42
+ assert res['dest'] == 'abc'
+
def test_group_add_and_get(self):
parser = parseopt.Parser()
group = parser.getgroup("hello", description="desc")
@@ -36,7 +72,7 @@
group = parseopt.OptionGroup("hello")
group.addoption("--option1", action="store_true")
assert len(group.options) == 1
- assert isinstance(group.options[0], py.std.optparse.Option)
+ assert isinstance(group.options[0], parseopt.Argument)
def test_group_shortopt_lowercase(self):
parser = parseopt.Parser()
@@ -58,19 +94,19 @@
def test_parse(self):
parser = parseopt.Parser()
parser.addoption("--hello", dest="hello", action="store")
- option, args = parser.parse(['--hello', 'world'])
- assert option.hello == "world"
- assert not args
+ args = parser.parse(['--hello', 'world'])
+ assert args.hello == "world"
+ assert not getattr(args, parseopt.Config._file_or_dir)
- def test_parse(self):
+ def test_parse2(self):
parser = parseopt.Parser()
- option, args = parser.parse([py.path.local()])
- assert args[0] == py.path.local()
+ args = parser.parse([py.path.local()])
+ assert getattr(args, parseopt.Config._file_or_dir)[0] == py.path.local()
def test_parse_will_set_default(self):
parser = parseopt.Parser()
parser.addoption("--hello", dest="hello", default="x", action="store")
- option, args = parser.parse([])
+ option = parser.parse([])
assert option.hello == "x"
del option.hello
args = parser.parse_setoption([], option)
@@ -87,28 +123,37 @@
assert option.world == 42
assert not args
+ def test_parse_special_destination(self):
+ parser = parseopt.Parser()
+ x = parser.addoption("--ultimate-answer", type=int)
+ args = parser.parse(['--ultimate-answer', '42'])
+ assert args.ultimate_answer == 42
+
def test_parse_defaultgetter(self):
def defaultget(option):
- if option.type == "int":
+ if not hasattr(option, 'type'):
+ return
+ if option.type is int:
option.default = 42
- elif option.type == "string":
+ elif option.type is str:
option.default = "world"
parser = parseopt.Parser(processopt=defaultget)
parser.addoption("--this", dest="this", type="int", action="store")
parser.addoption("--hello", dest="hello", type="string", action="store")
parser.addoption("--no", dest="no", action="store_true")
- option, args = parser.parse([])
+ option = parser.parse([])
assert option.hello == "world"
assert option.this == 42
-
+ assert option.no is False
@pytest.mark.skipif("sys.version_info < (2,5)")
def test_addoption_parser_epilog(testdir):
testdir.makeconftest("""
def pytest_addoption(parser):
parser.hints.append("hello world")
+ parser.hints.append("from me too")
""")
result = testdir.runpytest('--help')
#assert result.ret != 0
- result.stdout.fnmatch_lines(["*hint: hello world*"])
+ result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"])
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 Jul 26 08:59:15 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Fri, 26 Jul 2013 06:59:15 -0000
Subject: [Pytest-commit] commit/pytest: 3 new changesets
Message-ID: <20130726065915.20976.55488@app07.ash-private.bitbucket.org>
3 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/1fdb76c818cc/
Changeset: 1fdb76c818cc
Branch: tox_reference
User: Anthon van der Neut
Date: 2013-07-26 08:14:49
Summary: updated tox to live on testrun.org (the old links are still
working on codespeak.net, but those docs are outdated)
Affected #: 3 files
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 1fdb76c818cced9375ca593369558ac764280be1 doc/en/goodpractises.txt
--- a/doc/en/goodpractises.txt
+++ b/doc/en/goodpractises.txt
@@ -23,7 +23,7 @@
If you frequently release code to the public you
may want to look into `tox`_, the virtualenv test automation
-tool and its `pytest support `_.
+tool and its `pytest support `_.
The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up
and generate reports.
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 1fdb76c818cced9375ca593369558ac764280be1 doc/en/links.inc
--- a/doc/en/links.inc
+++ b/doc/en/links.inc
@@ -17,5 +17,5 @@
.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv
.. _hudson: http://hudson-ci.org/
.. _jenkins: http://jenkins-ci.org/
-.. _tox: http://codespeak.net/tox
+.. _tox: http://testrun.org/tox
.. _pylib: http://pylib.org
diff -r abfc7dc64ed4f5a50e917ac8a30863be7e2361a7 -r 1fdb76c818cced9375ca593369558ac764280be1 doc/en/projects.txt
--- a/doc/en/projects.txt
+++ b/doc/en/projects.txt
@@ -26,7 +26,7 @@
`16000 tests `_
* the `MoinMoin `_ Wiki Engine
* `sentry `_, realtime app-maintenance and exception tracking
-* `tox `_, virtualenv/Hudson integration tool
+* `tox `_, virtualenv/Hudson integration tool
* `PIDA `_ framework for integrated development
* `PyPM `_ ActiveState's package manager
* `Fom `_ a fluid object mapper for FluidDB
https://bitbucket.org/hpk42/pytest/commits/40a882235eae/
Changeset: 40a882235eae
Branch: tox_reference
User: Anthon van der Neut
Date: 2013-07-26 08:20:26
Summary: also update testrun.org in ???
Affected #: 3 files
diff -r 1fdb76c818cced9375ca593369558ac764280be1 -r 40a882235eaeb6553941602db8bd3bf1222eb876 doc/ja/goodpractises.txt
--- a/doc/ja/goodpractises.txt
+++ b/doc/ja/goodpractises.txt
@@ -39,11 +39,11 @@
..
If you frequently release code to the public you
may want to look into `tox`_, the virtualenv test automation
- tool and its `pytest support `_.
+ tool and its `pytest support `_.
The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up
and generate reports.
-???????????????????????virtualenv ?????????? `pytest ???? `_ ??? `tox`_ ??????????????????????? ``--junitxml=PATH`` ???????? JUnitXML ?????????????? Jenkins_ ???????????????????????????????????????????
+???????????????????????virtualenv ?????????? `pytest ???? `_ ??? `tox`_ ??????????????????????? ``--junitxml=PATH`` ???????? JUnitXML ?????????????? Jenkins_ ???????????????????????????????????????????
.. _standalone:
.. _`genscript method`:
diff -r 1fdb76c818cced9375ca593369558ac764280be1 -r 40a882235eaeb6553941602db8bd3bf1222eb876 doc/ja/links.inc
--- a/doc/ja/links.inc
+++ b/doc/ja/links.inc
@@ -17,4 +17,4 @@
.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv
.. _hudson: http://hudson-ci.org/
.. _jenkins: http://jenkins-ci.org/
-.. _tox: http://codespeak.net/tox
+.. _tox: http://testrun.org/tox
diff -r 1fdb76c818cced9375ca593369558ac764280be1 -r 40a882235eaeb6553941602db8bd3bf1222eb876 doc/ja/projects.txt
--- a/doc/ja/projects.txt
+++ b/doc/ja/projects.txt
@@ -16,7 +16,7 @@
* `PyPy `_, Python with a JIT compiler, running over
`16000 tests `_
* the `MoinMoin `_ Wiki Engine
- * `tox `_, virtualenv/Hudson integration tool
+ * `tox `_, virtualenv/Hudson integration tool
* `PIDA `_ framework for integrated development
* `PyPM `_ ActiveState's package manager
* `Fom `_ a fluid object mapper for FluidDB
@@ -49,7 +49,7 @@
* `PyPy `_: JIT ?????????? Python? `16000 ??? `_ ?????
* `MoinMoin `_: Wiki ????
-* `tox `_: virtualenv/Jenkins ????????????
+* `tox `_: virtualenv/Jenkins ????????????
* `PIDA `_: ???????????
* `PyPM `_: Activestate ?????????????
* `Fom `_: FluidDB ? fluid ??????????
https://bitbucket.org/hpk42/pytest/commits/e45e0210341c/
Changeset: e45e0210341c
User: hpk42
Date: 2013-07-26 08:59:12
Summary: Merged in anthon_van_der_neut/pytest/tox_reference (pull request #47)
update for links to tox
Affected #: 6 files
diff -r 4405d5fd6caec4072177911d9af4e1c57fe66cec -r e45e0210341cfc1bacfe27c3edf92079c3d40d4b doc/en/goodpractises.txt
--- a/doc/en/goodpractises.txt
+++ b/doc/en/goodpractises.txt
@@ -23,7 +23,7 @@
If you frequently release code to the public you
may want to look into `tox`_, the virtualenv test automation
-tool and its `pytest support `_.
+tool and its `pytest support `_.
The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up
and generate reports.
diff -r 4405d5fd6caec4072177911d9af4e1c57fe66cec -r e45e0210341cfc1bacfe27c3edf92079c3d40d4b doc/en/links.inc
--- a/doc/en/links.inc
+++ b/doc/en/links.inc
@@ -17,5 +17,5 @@
.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv
.. _hudson: http://hudson-ci.org/
.. _jenkins: http://jenkins-ci.org/
-.. _tox: http://codespeak.net/tox
+.. _tox: http://testrun.org/tox
.. _pylib: http://pylib.org
diff -r 4405d5fd6caec4072177911d9af4e1c57fe66cec -r e45e0210341cfc1bacfe27c3edf92079c3d40d4b doc/en/projects.txt
--- a/doc/en/projects.txt
+++ b/doc/en/projects.txt
@@ -26,7 +26,7 @@
`16000 tests `_
* the `MoinMoin `_ Wiki Engine
* `sentry `_, realtime app-maintenance and exception tracking
-* `tox `_, virtualenv/Hudson integration tool
+* `tox `_, virtualenv/Hudson integration tool
* `PIDA `_ framework for integrated development
* `PyPM `_ ActiveState's package manager
* `Fom `_ a fluid object mapper for FluidDB
diff -r 4405d5fd6caec4072177911d9af4e1c57fe66cec -r e45e0210341cfc1bacfe27c3edf92079c3d40d4b doc/ja/goodpractises.txt
--- a/doc/ja/goodpractises.txt
+++ b/doc/ja/goodpractises.txt
@@ -39,11 +39,11 @@
..
If you frequently release code to the public you
may want to look into `tox`_, the virtualenv test automation
- tool and its `pytest support `_.
+ tool and its `pytest support `_.
The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up
and generate reports.
-???????????????????????virtualenv ?????????? `pytest ???? `_ ??? `tox`_ ??????????????????????? ``--junitxml=PATH`` ???????? JUnitXML ?????????????? Jenkins_ ???????????????????????????????????????????
+???????????????????????virtualenv ?????????? `pytest ???? `_ ??? `tox`_ ??????????????????????? ``--junitxml=PATH`` ???????? JUnitXML ?????????????? Jenkins_ ???????????????????????????????????????????
.. _standalone:
.. _`genscript method`:
diff -r 4405d5fd6caec4072177911d9af4e1c57fe66cec -r e45e0210341cfc1bacfe27c3edf92079c3d40d4b doc/ja/links.inc
--- a/doc/ja/links.inc
+++ b/doc/ja/links.inc
@@ -17,4 +17,4 @@
.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv
.. _hudson: http://hudson-ci.org/
.. _jenkins: http://jenkins-ci.org/
-.. _tox: http://codespeak.net/tox
+.. _tox: http://testrun.org/tox
diff -r 4405d5fd6caec4072177911d9af4e1c57fe66cec -r e45e0210341cfc1bacfe27c3edf92079c3d40d4b doc/ja/projects.txt
--- a/doc/ja/projects.txt
+++ b/doc/ja/projects.txt
@@ -16,7 +16,7 @@
* `PyPy `_, Python with a JIT compiler, running over
`16000 tests `_
* the `MoinMoin `_ Wiki Engine
- * `tox `_, virtualenv/Hudson integration tool
+ * `tox `_, virtualenv/Hudson integration tool
* `PIDA `_ framework for integrated development
* `PyPM `_ ActiveState's package manager
* `Fom `_ a fluid object mapper for FluidDB
@@ -49,7 +49,7 @@
* `PyPy `_: JIT ?????????? Python? `16000 ??? `_ ?????
* `MoinMoin `_: Wiki ????
-* `tox `_: virtualenv/Jenkins ????????????
+* `tox `_: virtualenv/Jenkins ????????????
* `PIDA `_: ???????????
* `PyPM `_: Activestate ?????????????
* `Fom `_: FluidDB ? fluid ??????????
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 Jul 26 08:59:42 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Fri, 26 Jul 2013 06:59:42 -0000
Subject: [Pytest-commit] commit/pytest: 3 new changesets
Message-ID: <20130726065942.613.70622@app19.ash-private.bitbucket.org>
3 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/18a65f4e8303/
Changeset: 18a65f4e8303
User: hpk42
Date: 2013-07-26 07:51:33
Summary: add changelog: integrate option tab-completion when argcomplete is used. Thanks
Anthon van der Neut for the PR. This also lets pytest use argparse
instead of optparse.
Affected #: 2 files
diff -r 4405d5fd6caec4072177911d9af4e1c57fe66cec -r 18a65f4e83033fb6ceaaf34b89bffee493f71f6d AUTHORS
--- a/AUTHORS
+++ b/AUTHORS
@@ -34,3 +34,4 @@
Brian Okken
Katarzyna Jachim
Christian Theunert
+Anthon van der Neut
diff -r 4405d5fd6caec4072177911d9af4e1c57fe66cec -r 18a65f4e83033fb6ceaaf34b89bffee493f71f6d CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,10 @@
Changes between 2.3.5 and 2.4.DEV
-----------------------------------
+- integrate option tab-completion when argcomplete is used. Thanks
+ Anthon van der Neut for the PR. This also lets pytest use argparse
+ instead of optparse.
+
- SO-17664702: call fixture finalizers even if the fixture function
partially failed (finalizers would not always be called before)
https://bitbucket.org/hpk42/pytest/commits/31bc337af337/
Changeset: 31bc337af337
User: hpk42
Date: 2013-07-26 08:59:29
Summary: merge doc changes
Affected #: 6 files
diff -r 18a65f4e83033fb6ceaaf34b89bffee493f71f6d -r 31bc337af337227d596eff0810bd9aa63b796dbc doc/en/goodpractises.txt
--- a/doc/en/goodpractises.txt
+++ b/doc/en/goodpractises.txt
@@ -23,7 +23,7 @@
If you frequently release code to the public you
may want to look into `tox`_, the virtualenv test automation
-tool and its `pytest support `_.
+tool and its `pytest support `_.
The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up
and generate reports.
diff -r 18a65f4e83033fb6ceaaf34b89bffee493f71f6d -r 31bc337af337227d596eff0810bd9aa63b796dbc doc/en/links.inc
--- a/doc/en/links.inc
+++ b/doc/en/links.inc
@@ -17,5 +17,5 @@
.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv
.. _hudson: http://hudson-ci.org/
.. _jenkins: http://jenkins-ci.org/
-.. _tox: http://codespeak.net/tox
+.. _tox: http://testrun.org/tox
.. _pylib: http://pylib.org
diff -r 18a65f4e83033fb6ceaaf34b89bffee493f71f6d -r 31bc337af337227d596eff0810bd9aa63b796dbc doc/en/projects.txt
--- a/doc/en/projects.txt
+++ b/doc/en/projects.txt
@@ -26,7 +26,7 @@
`16000 tests `_
* the `MoinMoin `_ Wiki Engine
* `sentry `_, realtime app-maintenance and exception tracking
-* `tox `_, virtualenv/Hudson integration tool
+* `tox `_, virtualenv/Hudson integration tool
* `PIDA `_ framework for integrated development
* `PyPM `_ ActiveState's package manager
* `Fom `_ a fluid object mapper for FluidDB
diff -r 18a65f4e83033fb6ceaaf34b89bffee493f71f6d -r 31bc337af337227d596eff0810bd9aa63b796dbc doc/ja/goodpractises.txt
--- a/doc/ja/goodpractises.txt
+++ b/doc/ja/goodpractises.txt
@@ -39,11 +39,11 @@
..
If you frequently release code to the public you
may want to look into `tox`_, the virtualenv test automation
- tool and its `pytest support `_.
+ tool and its `pytest support `_.
The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up
and generate reports.
-???????????????????????virtualenv ?????????? `pytest ???? `_ ??? `tox`_ ??????????????????????? ``--junitxml=PATH`` ???????? JUnitXML ?????????????? Jenkins_ ???????????????????????????????????????????
+???????????????????????virtualenv ?????????? `pytest ???? `_ ??? `tox`_ ??????????????????????? ``--junitxml=PATH`` ???????? JUnitXML ?????????????? Jenkins_ ???????????????????????????????????????????
.. _standalone:
.. _`genscript method`:
diff -r 18a65f4e83033fb6ceaaf34b89bffee493f71f6d -r 31bc337af337227d596eff0810bd9aa63b796dbc doc/ja/links.inc
--- a/doc/ja/links.inc
+++ b/doc/ja/links.inc
@@ -17,4 +17,4 @@
.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv
.. _hudson: http://hudson-ci.org/
.. _jenkins: http://jenkins-ci.org/
-.. _tox: http://codespeak.net/tox
+.. _tox: http://testrun.org/tox
diff -r 18a65f4e83033fb6ceaaf34b89bffee493f71f6d -r 31bc337af337227d596eff0810bd9aa63b796dbc doc/ja/projects.txt
--- a/doc/ja/projects.txt
+++ b/doc/ja/projects.txt
@@ -16,7 +16,7 @@
* `PyPy `_, Python with a JIT compiler, running over
`16000 tests `_
* the `MoinMoin `_ Wiki Engine
- * `tox `_, virtualenv/Hudson integration tool
+ * `tox `_, virtualenv/Hudson integration tool
* `PIDA `_ framework for integrated development
* `PyPM `_ ActiveState's package manager
* `Fom `_ a fluid object mapper for FluidDB
@@ -49,7 +49,7 @@
* `PyPy `_: JIT ?????????? Python? `16000 ??? `_ ?????
* `MoinMoin `_: Wiki ????
-* `tox `_: virtualenv/Jenkins ????????????
+* `tox `_: virtualenv/Jenkins ????????????
* `PIDA `_: ???????????
* `PyPM `_: Activestate ?????????????
* `Fom `_: FluidDB ? fluid ??????????
https://bitbucket.org/hpk42/pytest/commits/085883326638/
Changeset: 085883326638
User: hpk42
Date: 2013-07-26 08:59:31
Summary: make genscript provide information as to compatibility
(now that argparse is a dependency on python2.6)
Affected #: 7 files
diff -r 31bc337af337227d596eff0810bd9aa63b796dbc -r 085883326638467e244499fb4c781452ad850548 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,9 +1,12 @@
Changes between 2.3.5 and 2.4.DEV
-----------------------------------
-- integrate option tab-completion when argcomplete is used. Thanks
- Anthon van der Neut for the PR. This also lets pytest use argparse
- instead of optparse.
+- 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)
@@ -68,6 +71,13 @@
- better parametrize error messages, thanks Brianna Laugher
+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
-----------------------------------
diff -r 31bc337af337227d596eff0810bd9aa63b796dbc -r 085883326638467e244499fb4c781452ad850548 _pytest/genscript.py
--- a/_pytest/genscript.py
+++ b/_pytest/genscript.py
@@ -1,5 +1,6 @@
""" generate a single-file self-contained version of py.test """
import py
+import sys
def find_toplevel(name):
for syspath in py.std.sys.path:
@@ -59,11 +60,21 @@
def pytest_cmdline_main(config):
genscript = config.getvalue("genscript")
if genscript:
+ tw = py.io.TerminalWriter()
+ deps = ['py', '_pytest', 'pytest']
+ if sys.version_info < (2,7):
+ deps.append("argparse")
+ tw.line("generated script will run on python2.5-python3.3++")
+ else:
+ tw.line("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", red=True)
script = generate_script(
'import py; raise SystemExit(py.test.cmdline.main())',
- ['py', '_pytest', 'pytest'],
+ deps,
)
-
genscript = py.path.local(genscript)
genscript.write(script)
+ tw.line("generated pytest standalone script: %s" % genscript,
+ bold=True)
return 0
diff -r 31bc337af337227d596eff0810bd9aa63b796dbc -r 085883326638467e244499fb4c781452ad850548 _pytest/standalonetemplate.py
--- a/_pytest/standalonetemplate.py
+++ b/_pytest/standalonetemplate.py
@@ -13,6 +13,10 @@
self.sources = sources
def find_module(self, fullname, path=None):
+ if fullname == "argparse" and sys.version_info >= (2,7):
+ # we were generated with =1.4.15"]
+ if sys.version_info < (2,7):
+ install_requires.append("argparse")
+
setup(
name='pytest',
description='py.test: simple powerful testing with Python',
@@ -21,7 +25,7 @@
entry_points= make_entry_points(),
cmdclass = {'test': PyTest},
# the following should be enabled for release
- install_requires=['py>=1.4.14'],
+ install_requires=install_requires,
classifiers=['Development Status :: 6 - Mature',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
diff -r 31bc337af337227d596eff0810bd9aa63b796dbc -r 085883326638467e244499fb4c781452ad850548 testing/conftest.py
--- a/testing/conftest.py
+++ b/testing/conftest.py
@@ -77,6 +77,9 @@
'python2.5': r'C:\Python25\python.exe',
'python2.4': r'C:\Python24\python.exe',
'python3.1': r'C:\Python31\python.exe',
+ 'python3.2': r'C:\Python32\python.exe',
+ 'python3.3': r'C:\Python33\python.exe',
+ 'python3.4': r'C:\Python34\python.exe',
}
def getexecutable(name, cache={}):
diff -r 31bc337af337227d596eff0810bd9aa63b796dbc -r 085883326638467e244499fb4c781452ad850548 testing/test_genscript.py
--- a/testing/test_genscript.py
+++ b/testing/test_genscript.py
@@ -1,10 +1,11 @@
+import pytest
import py, os, sys
import subprocess
-def pytest_funcarg__standalone(request):
- return request.cached_setup(scope="module",
- setup=lambda: Standalone(request))
+ at pytest.fixture(scope="module")
+def standalone(request):
+ return Standalone(request)
class Standalone:
def __init__(self, request):
@@ -20,6 +21,12 @@
return testdir._run(anypython, self.script, *args)
def test_gen(testdir, anypython, standalone):
+ if sys.version_info >= (2,7):
+ result = testdir._run(anypython, "-c",
+ "import sys;print sys.version_info >=(2,7)")
+ if result.stdout.str() == "False":
+ pytest.skip("genscript called from python2.7 cannot work "
+ "earlier python versions")
result = standalone.run(anypython, testdir, '--version')
assert result.ret == 0
result.stderr.fnmatch_lines([
diff -r 31bc337af337227d596eff0810bd9aa63b796dbc -r 085883326638467e244499fb4c781452ad850548 testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
import py, pytest
from _pytest import config as parseopt
from textwrap import dedent
@@ -44,7 +45,7 @@
res = argument.attrs()
assert res['default'] == 42
assert res['dest'] == 'abc'
-
+
def test_group_add_and_get(self):
parser = parseopt.Parser()
group = parser.getgroup("hello", description="desc")
@@ -128,7 +129,7 @@
x = parser.addoption("--ultimate-answer", type=int)
args = parser.parse(['--ultimate-answer', '42'])
assert args.ultimate_answer == 42
-
+
def test_parse_defaultgetter(self):
def defaultget(option):
if not hasattr(option, 'type'):
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 Jul 26 09:08:38 2013
From: notifications at travis-ci.org (Travis CI)
Date: Fri, 26 Jul 2013 07:08:38 +0000
Subject: [Pytest-commit] [Still Failing] hpk42/pytest#23 (master - 7f98273)
Message-ID: <51f22075cf850_22afff0182357@3bd4a3b1-b925-4c40-b0b5-c27b621e98e0.mail>
Build Update for hpk42/pytest
-------------------------------------
Build: #23
Status: Still Failing
Duration: 4 minutes and 15 seconds
Commit: 7f98273 (master)
Author: holger krekel
Message: make genscript provide information as to compatibility
(now that argparse is a dependency on python2.6)
View the changeset: https://github.com/hpk42/pytest/compare/d1dec1e32cb1...7f982737adab
View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/9505744
--
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 Jul 27 17:14:59 2013
From: issues-reply at bitbucket.org (anthon_van_der_neut)
Date: Sat, 27 Jul 2013 15:14:59 -0000
Subject: [Pytest-commit] Issue #107: provide smart Completers for
argcomplete (hpk42/tox)
Message-ID: <20130727151459.23684.63992@app01.ash-private.bitbucket.org>
New issue 107: provide smart Completers for argcomplete
https://bitbucket.org/hpk42/tox/issue/107/provide-smart-completers-for-argcomplete
anthon_van_der_neut:
To Do:
- tox -e could autocomplete with the sections marked in tox.ini ( + all)
From commits-noreply at bitbucket.org Mon Jul 29 15:39:33 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Mon, 29 Jul 2013 13:39:33 -0000
Subject: [Pytest-commit] commit/pytest: hpk42: be more liberal with respect
to lsof checks because jenkins keeps some files open
Message-ID: <20130729133933.12661.23847@app07.ash-private.bitbucket.org>
1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/1530d0e3abf3/
Changeset: 1530d0e3abf3
User: hpk42
Date: 2013-07-29 15:39:24
Summary: be more liberal with respect to lsof checks because jenkins keeps some files open
Affected #: 1 file
diff -r 085883326638467e244499fb4c781452ad850548 -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c testing/conftest.py
--- a/testing/conftest.py
+++ b/testing/conftest.py
@@ -36,7 +36,7 @@
def check_open_files(config):
out2 = py.process.cmdexec("lsof -p %d" % pid)
lines2 = getopenfiles(out2)
- if len(lines2) > config._numfiles + 1:
+ if len(lines2) > config._numfiles + 3:
error = []
error.append("***** %s FD leackage detected" %
(len(lines2)-config._numfiles))
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 Mon Jul 29 15:46:10 2013
From: notifications at travis-ci.org (Travis CI)
Date: Mon, 29 Jul 2013 13:46:10 +0000
Subject: [Pytest-commit] [Still Failing] hpk42/pytest#24 (master - aec5ccc)
Message-ID: <51f6722265ce8_22d7e4647e@42e72664-fec9-4b8a-98c0-53e4d1b45986.mail>
Build Update for hpk42/pytest
-------------------------------------
Build: #24
Status: Still Failing
Duration: 5 minutes and 44 seconds
Commit: aec5ccc (master)
Author: holger krekel
Message: be more liberal with respect to lsof checks because jenkins keeps some files open
View the changeset: https://github.com/hpk42/pytest/compare/7f982737adab...aec5ccc1961f
View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/9604749
--
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 Jul 31 07:51:09 2013
From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org)
Date: Wed, 31 Jul 2013 05:51:09 -0000
Subject: [Pytest-commit] commit/pytest: 3 new changesets
Message-ID: <20130731055109.29225.71564@app04.ash-private.bitbucket.org>
3 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/8c92bc4c65aa/
Changeset: 8c92bc4c65aa
Branch: argcomplete
User: Anthon van der Neut
Date: 2013-07-30 11:26:15
Summary: Fixes for argcomplete
- separate out most argcomplete related stuff in new file _argcomplete.py
(could probably be in the py library)
- allow positional arguments to be interspaced with optional arguments
( + test in test_parseopt.py )
- removed double argument in tox.ini
- add documentation on installing argcomplete (>=0.5.7 as needed for
Python 3), might need improving/incorporation in index.
This does not work on 2.5 yet. I have patches for argcomplete
(with/print()/"".format) but I am not sure they will be accepted.
Agreed with hpk not to push for that.
Removing argcomplete and leaving completion code active now works by early
exit, so no longer re-runs the programs without parameters
(which took long for py.test)
test calls bash with a script that redirects filedescriptor 8 (as used by
argcomplete), so the result can be tested.
Affected #: 5 files
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c _pytest/_argcomplete.py
--- /dev/null
+++ b/_pytest/_argcomplete.py
@@ -0,0 +1,68 @@
+
+"""allow bash-completion for argparse with argcomplete if installed
+needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
+to find the magic string, so _ARGCOMPLETE env. var is never set, and
+this does not need special code.
+
+argcomplete does not support python 2.5 (although the changes for that
+are minor).
+
+Function try_argcomplete(parser) should be called directly before
+the call to ArgumentParser.parse_args().
+
+The filescompleter is what you normally would use on the positional
+arguments specification, in order to get "dirname/" after "dirn"
+instead of the default "dirname ":
+
+ optparser.add_argument(Config._file_or_dir, nargs='*'
+ ).completer=filescompleter
+
+Other, application specific, completers should go in the file
+doing the add_argument calls as they need to be specified as .completer
+attributes as well. (If argcomplete is not installed, the function the
+attribute points to will not be used).
+
+---
+To include this support in another application that has setup.py generated
+scripts:
+- add the line:
+ # PYTHON_ARGCOMPLETE_OK
+ near the top of the main python entry point
+- include in the file calling parse_args():
+ from _argcomplete import try_argcomplete, filescompleter
+ , call try_argcomplete just before parse_args(), and optionally add
+ filescompleter to the positional arguments' add_argument()
+If things do not work right away:
+- switch on argcomplete debugging with (also helpful when doing custom
+ completers):
+ export _ARC_DEBUG=1
+- run:
+ python-argcomplete-check-easy-install-script $(which appname)
+ echo $?
+ will echo 0 if the magic line has been found, 1 if not
+- sometimes it helps to find early on errors using:
+ _ARGCOMPLETE=1 _ARC_DEBUG=1 appname
+ which should throw a KeyError: 'COMPLINE' (which is properly set by the
+ global argcomplete script).
+
+"""
+
+import sys
+import os
+
+if os.environ.get('_ARGCOMPLETE'):
+ # argcomplete 0.5.6 is not compatible with python 2.5.6: print/with/format
+ if sys.version_info[:2] < (2, 6):
+ sys.exit(1)
+ try:
+ import argcomplete
+ import argcomplete.completers
+ except ImportError:
+ sys.exit(-1)
+ filescompleter = argcomplete.completers.FilesCompleter()
+
+ def try_argcomplete(parser):
+ argcomplete.autocomplete(parser)
+else:
+ def try_argcomplete(parser): pass
+ filescompleter = None
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -4,6 +4,7 @@
import sys, os
from _pytest.core import PluginManager
import pytest
+from _argcomplete import try_argcomplete, filescompleter
# enable after some grace period for plugin writers
TYPE_WARN = False
@@ -91,7 +92,9 @@
n = option.names()
a = option.attrs()
arggroup.add_argument(*n, **a)
- optparser.add_argument(Config._file_or_dir, nargs='*')
+ # bash like autocompletion for dirs (appending '/')
+ optparser.add_argument(Config._file_or_dir, nargs='*'
+ ).completer=filescompleter
try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args])
@@ -115,13 +118,6 @@
self._inidict[name] = (help, type, default)
self._ininames.append(name)
-def try_argcomplete(parser):
- try:
- import argcomplete
- except ImportError:
- pass
- else:
- argcomplete.autocomplete(parser)
class ArgumentError(Exception):
"""
@@ -304,6 +300,7 @@
self._parser = parser
py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage,
add_help=False)
+
def format_epilog(self, formatter):
hints = self._parser.hints
if hints:
@@ -312,6 +309,18 @@
return s
return ""
+ def parse_args(self, args=None, namespace=None):
+ """allow splitting of positional arguments"""
+ args, argv = self.parse_known_args(args, namespace)
+ if argv:
+ for arg in argv:
+ if arg and arg[0] == '-':
+ msg = py.std.argparse._('unrecognized arguments: %s')
+ self.error(msg % ' '.join(argv))
+ getattr(args, Config._file_or_dir).extend(argv)
+ return args
+
+
class Conftest(object):
""" the single place for accessing values and interacting
towards conftest modules from py.test objects.
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c doc/en/bash-completion.txt
--- /dev/null
+++ b/doc/en/bash-completion.txt
@@ -0,0 +1,28 @@
+
+.. _bash_completion:
+
+Setting up bash completion
+==========================
+
+When using bash as your shell, ``py.test`` can use argcomplete
+(https://argcomplete.readthedocs.org/) for auto-completion.
+For this ``argcomplete`` needs to be installed **and** enabled.
+
+Install argcomplete using::
+
+ sudo pip install 'argcomplete>=0.5.7'
+
+For global activation of all argcomplete enabled python applications run::
+
+ sudo activate-global-python-argcomplete
+
+For permanent (but not global) ``py.test`` activation, use::
+
+ register-python-argcomplete py.test >> ~/.bashrc
+
+For one-time activation of argcomplete for ``py.test`` only, use::
+
+ eval "$(register-python-argcomplete py.test)"
+
+
+
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -130,6 +130,21 @@
args = parser.parse(['--ultimate-answer', '42'])
assert args.ultimate_answer == 42
+ def test_parse_split_positional_arguments(self):
+ parser = parseopt.Parser()
+ parser.addoption("-R", action='store_true')
+ parser.addoption("-S", action='store_false')
+ args = parser.parse(['-R', '4', '2', '-S'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ args = parser.parse(['-R', '-S', '4', '2', '-R'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ assert args.R == True
+ assert args.S == False
+ args = parser.parse(['-R', '4', '-S', '2'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ assert args.R == True
+ assert args.S == False
+
def test_parse_defaultgetter(self):
def defaultget(option):
if not hasattr(option, 'type'):
@@ -158,3 +173,28 @@
#assert result.ret != 0
result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"])
+ at pytest.mark.skipif("sys.version_info < (2,5)")
+def test_argcomplete(testdir):
+ import os
+ p = py.path.local.make_numbered_dir(prefix="test_argcomplete-",
+ keep=None, rootdir=testdir.tmpdir)
+ script = p._fastjoin('test_argcomplete')
+ with open(str(script), 'w') as fp:
+ # redirect output from argcomplete to stdin and stderr is not trivial
+ # http://stackoverflow.com/q/12589419/1307905
+ # so we use bash
+ fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" $(which py.test) '
+ '8>&1 9>&2')
+ os.environ['_ARGCOMPLETE'] = "1"
+ os.environ['_ARGCOMPLETE_IFS'] = "\x0b"
+ os.environ['COMP_LINE'] = "py.test --fu"
+ os.environ['COMP_POINT'] = "12"
+ os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:'
+
+ result = testdir.run('bash', str(script), '--fu')
+ print dir(result), result.ret
+ if result.ret == 255:
+ # argcomplete not found
+ assert True
+ else:
+ result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"])
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -43,7 +43,7 @@
deps=twisted
pexpect
commands=
- py.test -rsxf testing/test_unittest.py \
+ py.test -rsxf \
--junitxml={envlogdir}/junit-{envname}.xml {posargs:testing/test_unittest.py}
[testenv:doctest]
changedir=.
https://bitbucket.org/hpk42/pytest/commits/f44d44a4142b/
Changeset: f44d44a4142b
Branch: argcomplete
User: Anthon van der Neut
Date: 2013-07-30 12:33:38
Summary: minor adjustment, added test for positional argument completion
Affected #: 2 files
diff -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c -r f44d44a4142b72a260007e413e6419549b3c1dc1 _pytest/_argcomplete.py
--- a/_pytest/_argcomplete.py
+++ b/_pytest/_argcomplete.py
@@ -55,7 +55,6 @@
if sys.version_info[:2] < (2, 6):
sys.exit(1)
try:
- import argcomplete
import argcomplete.completers
except ImportError:
sys.exit(-1)
diff -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c -r f44d44a4142b72a260007e413e6419549b3c1dc1 testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -175,10 +175,10 @@
@pytest.mark.skipif("sys.version_info < (2,5)")
def test_argcomplete(testdir):
+ if not py.path.local.sysfind('bash'):
+ pytest.skip("bash not available")
import os
- p = py.path.local.make_numbered_dir(prefix="test_argcomplete-",
- keep=None, rootdir=testdir.tmpdir)
- script = p._fastjoin('test_argcomplete')
+ script = os.path.join(os.getcwd(), 'test_argcomplete')
with open(str(script), 'w') as fp:
# redirect output from argcomplete to stdin and stderr is not trivial
# http://stackoverflow.com/q/12589419/1307905
@@ -187,14 +187,22 @@
'8>&1 9>&2')
os.environ['_ARGCOMPLETE'] = "1"
os.environ['_ARGCOMPLETE_IFS'] = "\x0b"
- os.environ['COMP_LINE'] = "py.test --fu"
- os.environ['COMP_POINT'] = "12"
os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:'
- result = testdir.run('bash', str(script), '--fu')
+ arg = '--fu'
+ os.environ['COMP_LINE'] = "py.test " + arg
+ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE']))
+ result = testdir.run('bash', str(script), arg)
print dir(result), result.ret
if result.ret == 255:
# argcomplete not found
- assert True
+ pytest.skip("argcomplete not available")
else:
result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"])
+
+ os.mkdir('test_argcomplete.d')
+ arg = 'test_argc'
+ os.environ['COMP_LINE'] = "py.test " + arg
+ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE']))
+ result = testdir.run('bash', str(script), arg)
+ result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"])
https://bitbucket.org/hpk42/pytest/commits/73015defd88f/
Changeset: 73015defd88f
User: hpk42
Date: 2013-07-31 07:51:07
Summary: Merged in anthon_van_der_neut/pytest/argcomplete (pull request #50)
Fixes for argcomplete
Affected #: 5 files
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 73015defd88f6a45ba44fd6e109b03bc8b3e82e9 _pytest/_argcomplete.py
--- /dev/null
+++ b/_pytest/_argcomplete.py
@@ -0,0 +1,67 @@
+
+"""allow bash-completion for argparse with argcomplete if installed
+needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
+to find the magic string, so _ARGCOMPLETE env. var is never set, and
+this does not need special code.
+
+argcomplete does not support python 2.5 (although the changes for that
+are minor).
+
+Function try_argcomplete(parser) should be called directly before
+the call to ArgumentParser.parse_args().
+
+The filescompleter is what you normally would use on the positional
+arguments specification, in order to get "dirname/" after "dirn"
+instead of the default "dirname ":
+
+ optparser.add_argument(Config._file_or_dir, nargs='*'
+ ).completer=filescompleter
+
+Other, application specific, completers should go in the file
+doing the add_argument calls as they need to be specified as .completer
+attributes as well. (If argcomplete is not installed, the function the
+attribute points to will not be used).
+
+---
+To include this support in another application that has setup.py generated
+scripts:
+- add the line:
+ # PYTHON_ARGCOMPLETE_OK
+ near the top of the main python entry point
+- include in the file calling parse_args():
+ from _argcomplete import try_argcomplete, filescompleter
+ , call try_argcomplete just before parse_args(), and optionally add
+ filescompleter to the positional arguments' add_argument()
+If things do not work right away:
+- switch on argcomplete debugging with (also helpful when doing custom
+ completers):
+ export _ARC_DEBUG=1
+- run:
+ python-argcomplete-check-easy-install-script $(which appname)
+ echo $?
+ will echo 0 if the magic line has been found, 1 if not
+- sometimes it helps to find early on errors using:
+ _ARGCOMPLETE=1 _ARC_DEBUG=1 appname
+ which should throw a KeyError: 'COMPLINE' (which is properly set by the
+ global argcomplete script).
+
+"""
+
+import sys
+import os
+
+if os.environ.get('_ARGCOMPLETE'):
+ # argcomplete 0.5.6 is not compatible with python 2.5.6: print/with/format
+ if sys.version_info[:2] < (2, 6):
+ sys.exit(1)
+ try:
+ import argcomplete.completers
+ except ImportError:
+ sys.exit(-1)
+ filescompleter = argcomplete.completers.FilesCompleter()
+
+ def try_argcomplete(parser):
+ argcomplete.autocomplete(parser)
+else:
+ def try_argcomplete(parser): pass
+ filescompleter = None
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 73015defd88f6a45ba44fd6e109b03bc8b3e82e9 _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -4,6 +4,7 @@
import sys, os
from _pytest.core import PluginManager
import pytest
+from _argcomplete import try_argcomplete, filescompleter
# enable after some grace period for plugin writers
TYPE_WARN = False
@@ -91,7 +92,9 @@
n = option.names()
a = option.attrs()
arggroup.add_argument(*n, **a)
- optparser.add_argument(Config._file_or_dir, nargs='*')
+ # bash like autocompletion for dirs (appending '/')
+ optparser.add_argument(Config._file_or_dir, nargs='*'
+ ).completer=filescompleter
try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args])
@@ -115,13 +118,6 @@
self._inidict[name] = (help, type, default)
self._ininames.append(name)
-def try_argcomplete(parser):
- try:
- import argcomplete
- except ImportError:
- pass
- else:
- argcomplete.autocomplete(parser)
class ArgumentError(Exception):
"""
@@ -304,6 +300,7 @@
self._parser = parser
py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage,
add_help=False)
+
def format_epilog(self, formatter):
hints = self._parser.hints
if hints:
@@ -312,6 +309,18 @@
return s
return ""
+ def parse_args(self, args=None, namespace=None):
+ """allow splitting of positional arguments"""
+ args, argv = self.parse_known_args(args, namespace)
+ if argv:
+ for arg in argv:
+ if arg and arg[0] == '-':
+ msg = py.std.argparse._('unrecognized arguments: %s')
+ self.error(msg % ' '.join(argv))
+ getattr(args, Config._file_or_dir).extend(argv)
+ return args
+
+
class Conftest(object):
""" the single place for accessing values and interacting
towards conftest modules from py.test objects.
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 73015defd88f6a45ba44fd6e109b03bc8b3e82e9 doc/en/bash-completion.txt
--- /dev/null
+++ b/doc/en/bash-completion.txt
@@ -0,0 +1,28 @@
+
+.. _bash_completion:
+
+Setting up bash completion
+==========================
+
+When using bash as your shell, ``py.test`` can use argcomplete
+(https://argcomplete.readthedocs.org/) for auto-completion.
+For this ``argcomplete`` needs to be installed **and** enabled.
+
+Install argcomplete using::
+
+ sudo pip install 'argcomplete>=0.5.7'
+
+For global activation of all argcomplete enabled python applications run::
+
+ sudo activate-global-python-argcomplete
+
+For permanent (but not global) ``py.test`` activation, use::
+
+ register-python-argcomplete py.test >> ~/.bashrc
+
+For one-time activation of argcomplete for ``py.test`` only, use::
+
+ eval "$(register-python-argcomplete py.test)"
+
+
+
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 73015defd88f6a45ba44fd6e109b03bc8b3e82e9 testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -130,6 +130,21 @@
args = parser.parse(['--ultimate-answer', '42'])
assert args.ultimate_answer == 42
+ def test_parse_split_positional_arguments(self):
+ parser = parseopt.Parser()
+ parser.addoption("-R", action='store_true')
+ parser.addoption("-S", action='store_false')
+ args = parser.parse(['-R', '4', '2', '-S'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ args = parser.parse(['-R', '-S', '4', '2', '-R'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ assert args.R == True
+ assert args.S == False
+ args = parser.parse(['-R', '4', '-S', '2'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ assert args.R == True
+ assert args.S == False
+
def test_parse_defaultgetter(self):
def defaultget(option):
if not hasattr(option, 'type'):
@@ -158,3 +173,36 @@
#assert result.ret != 0
result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"])
+ at pytest.mark.skipif("sys.version_info < (2,5)")
+def test_argcomplete(testdir):
+ if not py.path.local.sysfind('bash'):
+ pytest.skip("bash not available")
+ import os
+ script = os.path.join(os.getcwd(), 'test_argcomplete')
+ with open(str(script), 'w') as fp:
+ # redirect output from argcomplete to stdin and stderr is not trivial
+ # http://stackoverflow.com/q/12589419/1307905
+ # so we use bash
+ fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" $(which py.test) '
+ '8>&1 9>&2')
+ os.environ['_ARGCOMPLETE'] = "1"
+ os.environ['_ARGCOMPLETE_IFS'] = "\x0b"
+ os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:'
+
+ arg = '--fu'
+ os.environ['COMP_LINE'] = "py.test " + arg
+ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE']))
+ result = testdir.run('bash', str(script), arg)
+ print dir(result), result.ret
+ if result.ret == 255:
+ # argcomplete not found
+ pytest.skip("argcomplete not available")
+ else:
+ result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"])
+
+ os.mkdir('test_argcomplete.d')
+ arg = 'test_argc'
+ os.environ['COMP_LINE'] = "py.test " + arg
+ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE']))
+ result = testdir.run('bash', str(script), arg)
+ result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"])
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r 73015defd88f6a45ba44fd6e109b03bc8b3e82e9 tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -43,7 +43,7 @@
deps=twisted
pexpect
commands=
- py.test -rsxf testing/test_unittest.py \
+ py.test -rsxf \
--junitxml={envlogdir}/junit-{envname}.xml {posargs:testing/test_unittest.py}
[testenv:doctest]
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 notifications at travis-ci.org Wed Jul 31 07:56:10 2013
From: notifications at travis-ci.org (Travis CI)
Date: Wed, 31 Jul 2013 05:56:10 +0000
Subject: [Pytest-commit] [Still Failing] hpk42/pytest#25 (master - 95f25c1)
Message-ID: <51f8a6fa95e70_23cc4229132@4beb259d-5ef4-49e8-ba4c-a8e21c5e90b0.mail>
Build Update for hpk42/pytest
-------------------------------------
Build: #25
Status: Still Failing
Duration: 3 minutes and 33 seconds
Commit: 95f25c1 (master)
Author: holger krekel
Message: Merged in anthon_van_der_neut/pytest/argcomplete (pull request #50)
Fixes for argcomplete
View the changeset: https://github.com/hpk42/pytest/compare/aec5ccc1961f...95f25c1bc1c3
View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/9679016
--
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: