[Pytest-commit] commit/pytest: 2 new changesets

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Fri Sep 27 10:22:05 CEST 2013


2 new commits in pytest:

https://bitbucket.org/hpk42/pytest/commits/a3261d045144/
Changeset:   a3261d045144
User:        hpk42
Date:        2013-09-27 09:49:39
Summary:     don't manipulate FDs at all if output capturing is turned off.
Affected #:  2 files

diff -r e4ca07d8ab69b50c6a13d04cbff8417d5a2ad0b0 -r a3261d045144baf409b00ca4a260727361d7f403 _pytest/terminal.py
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -34,9 +34,10 @@
 def pytest_configure(config):
     config.option.verbose -= config.option.quiet
     # we try hard to make printing resilient against
-    # later changes on FD level.
+    # later changes on FD level. (unless capturing is turned off)
     stdout = py.std.sys.stdout
-    if hasattr(os, 'dup') and hasattr(stdout, 'fileno'):
+    capture = config.option.capture != "no"
+    if capture and hasattr(os, 'dup') and hasattr(stdout, 'fileno'):
         try:
             newstdout = py.io.dupfile(stdout, buffering=1,
                                       encoding=stdout.encoding)

diff -r e4ca07d8ab69b50c6a13d04cbff8417d5a2ad0b0 -r a3261d045144baf409b00ca4a260727361d7f403 testing/test_terminal.py
--- a/testing/test_terminal.py
+++ b/testing/test_terminal.py
@@ -677,6 +677,13 @@
         "*2 passed*"
     ])
 
+def test_nofd_manipulation_with_capture_disabled(testdir):
+    from _pytest.terminal import pytest_configure
+    config = testdir.parseconfig("--capture=no")
+    stdout = sys.stdout
+    pytest_configure(config)
+    reporter = config.pluginmanager.getplugin('terminalreporter')
+    assert reporter._tw._file == stdout
 
 def test_tbstyle_native_setup_error(testdir):
     p = testdir.makepyfile("""
@@ -684,7 +691,7 @@
         @pytest.fixture
         def setup_error_fixture():
             raise Exception("error in exception")
-            
+
         def test_error_fixture(setup_error_fixture):
             pass
     """)


https://bitbucket.org/hpk42/pytest/commits/c1b01e0df4b3/
Changeset:   c1b01e0df4b3
User:        hpk42
Date:        2013-09-27 10:21:23
Summary:     rework docs to demonstrate and discuss current yield syntax in more depth.
Affected #:  3 files

diff -r a3261d045144baf409b00ca4a260727361d7f403 -r c1b01e0df4b3bb4bd865af33bf0134e1ef6d519e doc/en/apiref.txt
--- a/doc/en/apiref.txt
+++ b/doc/en/apiref.txt
@@ -11,6 +11,7 @@
    customize.txt
    assert.txt
    fixture.txt
+   yieldfixture.txt
    parametrize.txt
    xunit_setup.txt
    capture.txt

diff -r a3261d045144baf409b00ca4a260727361d7f403 -r c1b01e0df4b3bb4bd865af33bf0134e1ef6d519e doc/en/fixture.txt
--- a/doc/en/fixture.txt
+++ b/doc/en/fixture.txt
@@ -79,7 +79,7 @@
     ================================= FAILURES =================================
     ________________________________ test_ehlo _________________________________
     
-    smtp = <smtplib.SMTP instance at 0x1ac66c8>
+    smtp = <smtplib.SMTP instance at 0x22530e0>
     
         def test_ehlo(smtp):
             response, msg = smtp.ehlo()
@@ -198,7 +198,7 @@
     ================================= FAILURES =================================
     ________________________________ test_ehlo _________________________________
     
-    smtp = <smtplib.SMTP instance at 0x15b2d88>
+    smtp = <smtplib.SMTP instance at 0x165fa28>
     
         def test_ehlo(smtp):
             response = smtp.ehlo()
@@ -210,7 +210,7 @@
     test_module.py:6: AssertionError
     ________________________________ test_noop _________________________________
     
-    smtp = <smtplib.SMTP instance at 0x15b2d88>
+    smtp = <smtplib.SMTP instance at 0x165fa28>
     
         def test_noop(smtp):
             response = smtp.noop()
@@ -219,7 +219,7 @@
     E       assert 0
     
     test_module.py:11: AssertionError
-    ========================= 2 failed in 0.16 seconds =========================
+    ========================= 2 failed in 0.18 seconds =========================
 
 You see the two ``assert 0`` failing and more importantly you can also see 
 that the same (module-scoped) ``smtp`` object was passed into the two 
@@ -266,8 +266,7 @@
 
     $ py.test -s -q --tb=no
     FF
-    2 failed in 0.16 seconds
-    teardown smtp
+    2 failed in 0.20 seconds
 
 We see that the ``smtp`` instance is finalized after the two
 tests finished execution.  Note that if we decorated our fixture
@@ -276,8 +275,9 @@
 module itself does not need to change or know about these details
 of fixture setup.
 
-Note that pytest-2.4 introduced an alternative `yield-context <yieldctx>`_ 
-mechanism which allows to interact nicely with context managers.
+Note that pytest-2.4 introduced an experimental alternative
+:ref:`yield fixture mechanism <yieldctx>` for easier context manager integration
+and more linear writing of teardown code.
 
 .. _`request-context`:
 
@@ -310,8 +310,7 @@
 
     $ py.test -s -q --tb=no
     FF
-    2 failed in 0.17 seconds
-    teardown smtp
+    2 failed in 0.18 seconds
 
 Let's quickly create another test module that actually sets the
 server URL in its module namespace::
@@ -331,7 +330,7 @@
     ______________________________ test_showhelo _______________________________
     test_anothersmtp.py:5: in test_showhelo
     >       assert 0, smtp.helo()
-    E       AssertionError: (250, 'hq.merlinux.eu')
+    E       AssertionError: (250, 'mail.python.org')
 
 voila! The ``smtp`` fixture function picked up our mail server name
 from the module namespace.
@@ -378,7 +377,7 @@
     ================================= FAILURES =================================
     __________________________ test_ehlo[merlinux.eu] __________________________
     
-    smtp = <smtplib.SMTP instance at 0x1d1b680>
+    smtp = <smtplib.SMTP instance at 0x28d13b0>
     
         def test_ehlo(smtp):
             response = smtp.ehlo()
@@ -390,7 +389,7 @@
     test_module.py:6: AssertionError
     __________________________ test_noop[merlinux.eu] __________________________
     
-    smtp = <smtplib.SMTP instance at 0x1d1b680>
+    smtp = <smtplib.SMTP instance at 0x28d13b0>
     
         def test_noop(smtp):
             response = smtp.noop()
@@ -401,7 +400,7 @@
     test_module.py:11: AssertionError
     ________________________ test_ehlo[mail.python.org] ________________________
     
-    smtp = <smtplib.SMTP instance at 0x1d237e8>
+    smtp = <smtplib.SMTP instance at 0x28d8440>
     
         def test_ehlo(smtp):
             response = smtp.ehlo()
@@ -412,7 +411,7 @@
     test_module.py:5: AssertionError
     ________________________ test_noop[mail.python.org] ________________________
     
-    smtp = <smtplib.SMTP instance at 0x1d237e8>
+    smtp = <smtplib.SMTP instance at 0x28d8440>
     
         def test_noop(smtp):
             response = smtp.noop()
@@ -421,7 +420,7 @@
     E       assert 0
     
     test_module.py:11: AssertionError
-    4 failed in 6.04 seconds
+    4 failed in 6.47 seconds
 
 We see that our two test functions each ran twice, against the different
 ``smtp`` instances.  Note also, that with the ``mail.python.org`` 
@@ -462,14 +461,14 @@
     $ py.test -v test_appsetup.py
     =========================== test session starts ============================
     platform linux2 -- Python 2.7.3 -- pytest-2.4.0.dev12 -- /home/hpk/venv/0/bin/python
-    cachedir: /tmp/doc-exec-120/.cache
+    cachedir: /tmp/doc-exec-127/.cache
     plugins: xdist, pep8, cov, cache, capturelog, instafail
     collecting ... collected 2 items
     
     test_appsetup.py:12: test_smtp_exists[mail.python.org] PASSED
     test_appsetup.py:12: test_smtp_exists[merlinux.eu] PASSED
     
-    ========================= 2 passed in 6.98 seconds =========================
+    ========================= 2 passed in 6.07 seconds =========================
 
 Due to the parametrization of ``smtp`` the test will run twice with two
 different ``App`` instances and respective smtp servers.  There is no
@@ -528,30 +527,30 @@
     $ py.test -v -s test_module.py
     =========================== test session starts ============================
     platform linux2 -- Python 2.7.3 -- pytest-2.4.0.dev12 -- /home/hpk/venv/0/bin/python
-    cachedir: /tmp/doc-exec-120/.cache
+    cachedir: /tmp/doc-exec-127/.cache
     plugins: xdist, pep8, cov, cache, capturelog, instafail
     collecting ... collected 8 items
     
-    test_module.py:15: test_0[1] PASSED
-    test_module.py:15: test_0[2] PASSED
-    test_module.py:17: test_1[mod1] PASSED
-    test_module.py:19: test_2[1-mod1] PASSED
-    test_module.py:19: test_2[2-mod1] PASSED
-    test_module.py:17: test_1[mod2] PASSED
-    test_module.py:19: test_2[1-mod2] PASSED
-    test_module.py:19: test_2[2-mod2] PASSED
+    test_module.py:15: test_0[1]   test0 1
+    PASSED
+    test_module.py:15: test_0[2]   test0 2
+    PASSED
+    test_module.py:17: test_1[mod1] create mod1
+      test1 mod1
+    PASSED
+    test_module.py:19: test_2[1-mod1]   test2 1 mod1
+    PASSED
+    test_module.py:19: test_2[2-mod1]   test2 2 mod1
+    PASSED
+    test_module.py:17: test_1[mod2] create mod2
+      test1 mod2
+    PASSED
+    test_module.py:19: test_2[1-mod2]   test2 1 mod2
+    PASSED
+    test_module.py:19: test_2[2-mod2]   test2 2 mod2
+    PASSED
     
     ========================= 8 passed in 0.02 seconds =========================
-      test0 1
-      test0 2
-    create mod1
-      test1 mod1
-      test2 1 mod1
-      test2 2 mod1
-    create mod2
-      test1 mod2
-      test2 1 mod2
-      test2 2 mod2
 
 You can see that the parametrized module-scoped ``modarg`` resource caused
 an ordering of test execution that lead to the fewest possible "active" resources. The finalizer for the ``mod1`` parametrized resource was executed 
@@ -728,61 +727,3 @@
 ``conftest.py`` files and finally builtin and third party plugins.
 
 
-.. _yieldctx:
-
-Fixture functions using "yield" / context manager integration
----------------------------------------------------------------
-
-.. versionadded:: 2.4
-
-pytest-2.4 allows fixture functions to use a ``yield`` instead 
-of a ``return`` statement to provide a fixture value.  Let's
-look at a quick example before discussing advantages::
-
-    # content of conftest.py
-    
-    import smtplib
-    import pytest
-
-    @pytest.fixture(scope="module", yieldctx=True)
-    def smtp():
-        smtp = smtplib.SMTP("merlinux.eu")
-        yield smtp  # provide the fixture value
-        print ("teardown smtp after a yield")
-        smtp.close()
-
-In contrast to the `finalization`_ example, our fixture
-function uses a single ``yield`` to provide the ``smtp`` fixture
-value.  The code after the ``yield`` statement serves as the
-teardown code, avoiding the indirection of registering a 
-teardown function.   More importantly, it also allows to 
-seemlessly re-use existing context managers, for example::
-
-    @pytest.fixture(yieldctx=True)
-    def somefixture():
-        with open("somefile") as f:
-            yield f.readlines()
-
-The file ``f`` will be closed once ``somefixture`` goes out of scope.
-It is possible to achieve the same result by using a ``request.addfinalizer``
-call but it is more boilerplate and not very obvious unless
-you know about the exact ``__enter__|__exit__`` protocol of with-style
-context managers.
-
-For some background, here is the protocol pytest follows for when
-``yieldctx=True`` is specified in the fixture decorator:
-
-a) iterate once into the generator for producing the value
-b) iterate a second time for tearing the fixture down, expecting
-   a StopIteration (which is produced automatically from the Python 
-   runtime when the generator returns).
-
-The teardown will always execute, independently of the outcome of
-test functions.  You do **not need** to write the teardown code into a
-``try-finally`` clause like you would usually do with
-:py:func:`contextlib.contextmanager` decorated functions.
-
-If the fixture generator yields a second value pytest will report 
-an error.  Yielding cannot be used for parametrization, rather
-see `fixture-parametrize`_.
-

diff -r a3261d045144baf409b00ca4a260727361d7f403 -r c1b01e0df4b3bb4bd865af33bf0134e1ef6d519e doc/en/yieldfixture.txt
--- /dev/null
+++ b/doc/en/yieldfixture.txt
@@ -0,0 +1,132 @@
+
+.. _yieldctx:
+
+Fixture functions using "yield" / context manager integration
+---------------------------------------------------------------
+
+.. versionadded:: 2.4
+
+.. regendoc:wipe
+
+pytest-2.4 allows fixture functions to seemlessly use a ``yield`` instead 
+of a ``return`` statement to provide a fixture value while otherwise
+fully supporting all other fixture features.  
+
+.. note::
+
+   "yielding" fixture values is an experimental feature and its exact
+   declaration may change later but earliest in a 2.5 release.  You can thus
+   safely use this feature in the 2.4 series but may need to adapt your
+   fixtures later. Test functions themselves will not need to change
+   (they can be completely ignorant of the return/yield modes of 
+   fixture functions).
+
+Let's look at a simple standalone-example using the new ``yield`` syntax::
+
+    # content of test_yield.py
+    
+    import pytest
+
+    @pytest.fixture(yieldctx=True)
+    def passwd():
+        print ("\nsetup before yield")
+        f = open("/etc/passwd")
+        yield f.readlines()
+        print ("teardown after yield")
+        f.close()
+
+    def test_has_lines(passwd):
+        print ("test called")
+        assert passwd
+
+In contrast to :ref:`finalization through registering callbacks
+<finalization>`, our fixture function used a ``yield``
+statement to provide the lines of the ``/etc/passwd`` file.  
+The code after the ``yield`` statement serves as the teardown code, 
+avoiding the indirection of registering a teardown callback function.   
+
+Let's run it with output capturing disabled::
+
+    $ py.test -q -s test_yield.py
+    
+    setup before yield
+    test called
+    .teardown after yield
+    
+    1 passed in 0.01 seconds
+
+We can also seemlessly use the new syntax with ``with`` statements.
+Let's simplify the above ``passwd`` fixture::
+
+    # content of test_yield2.py
+    
+    import pytest
+
+    @pytest.fixture(yieldctx=True)
+    def passwd():
+        with open("/etc/passwd") as f:
+            yield f.readlines()
+
+    def test_has_lines(passwd):
+        assert len(passwd) >= 1
+
+The file ``f`` will be closed after the test finished execution
+because the Python ``file`` object supports finalization when
+the ``with`` statement ends. 
+
+Note that the new syntax is fully integrated with using ``scope``, 
+``params`` and other fixture features.  Changing existing 
+fixture functions to use ``yield`` is thus straight forward.
+
+Discussion and future considerations / feedback
+++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The yield-syntax has been discussed by pytest users extensively.
+In general, the advantages of the using a ``yield`` fixture syntax are:
+
+- easy provision of fixtures in conjunction with context managers. 
+
+- no need to register a callback, providing for more synchronous
+  control flow in the fixture function.  Also there is no need to accept
+  the ``request`` object into the fixture function just for providing
+  finalization code.
+
+However, there are also limitations or foreseeable irritations:
+
+- usually ``yield`` is typically used for producing multiple values.
+  But fixture functions can only yield exactly one value.
+  Yielding a second fixture value will get you an error.
+  It's possible we can evolve pytest to allow for producing
+  multiple values as an alternative to current parametrization.
+  For now, you can just use the normal
+  :ref:`fixture parametrization <fixture-parametrize>`
+  mechanisms together with ``yield``-style fixtures.
+
+- the ``yield`` syntax is similar to what
+  :py:func:`contextlib.contextmanager` decorated functions
+  provide.  With pytest fixture functions, the "after yield" part will  
+  always be invoked, independently from the exception status
+  of the test function which uses the fixture.   The pytest
+  behaviour makes sense if you consider that many different
+  test functions might use a module or session scoped fixture.
+  Some test functions might raise exceptions and others not,
+  so how could pytest re-raise a single exception at the
+  ``yield`` point in the fixture function?
+
+- lastly ``yield`` introduces more than one way to write
+  fixture functions, so what's the obvious way to a newcomer?
+  Newcomers reading the docs will see feature examples using the
+  ``return`` style so should use that, if in doubt.  
+  Others can start experimenting with writing yield-style fixtures
+  and possibly help evolving them further.
+
+Some developers also expressed their preference for
+rather introduce a new ``@pytest.yieldfixture`` decorator
+instead of a keyword argument, or for assuming the above 
+yield-semantics automatically by introspecting if a fixture 
+function is a generator.  Depending on more experiences and 
+feedback during the 2.4 cycle, we revisit theses issues.
+
+If you want to feedback or participate in the ongoing
+discussion, please join our :ref:`contact channels`.
+you are most welcome.

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.


More information about the pytest-commit mailing list