diff --git a/README.rst b/README.rst
index fe1b031..e919304 100644
--- a/README.rst
+++ b/README.rst
@@ -1,17 +1,49 @@
pytest-trio
===========
+.. image:: https://img.shields.io/badge/chat-join%20now-blue.svg
+ :target: https://gitter.im/python-trio/general
+ :alt: Join chatroom
+
+.. image:: https://img.shields.io/badge/docs-read%20now-blue.svg
+ :target: https://pytest-trio.readthedocs.io/en/latest/?badge=latest
+ :alt: Documentation Status
+
+.. image:: https://img.shields.io/pypi/v/pytest-trio.svg
+ :target: https://pypi.org/project/pytest-trio
+ :alt: Latest PyPi version
+
.. image:: https://travis-ci.org/python-trio/pytest-trio.svg?branch=master
- :target: https://travis-ci.org/python-trio/pytest-trio
+ :target: https://travis-ci.org/python-trio/pytest-trio
+ :alt: Automated test status (Linux and MacOS)
.. image:: https://ci.appveyor.com/api/projects/status/aq0pklx7hanx031x?svg=true
- :target: https://ci.appveyor.com/project/touilleMan/pytest-trio
+ :target: https://ci.appveyor.com/project/touilleMan/pytest-trio
+ :alt: Automated test status (Windows)
.. image:: https://codecov.io/gh/python-trio/pytest-trio/branch/master/graph/badge.svg
- :target: https://codecov.io/gh/python-trio/pytest-trio
+ :target: https://codecov.io/gh/python-trio/pytest-trio
+ :alt: Test coverage
+
+This is a pytest plugin to help you test projects that use `Trio
+`__, a friendly library for concurrency
+and async I/O in Python. For an overview of features, see our `manual
+`__, or jump straight to the
+`quickstart guide
+`__.
+
+
+Vital statistics
+----------------
+
+**Documentation:** https://pytest-trio.readthedocs.io
-Welcome to `pytest-trio `__!
+**Bug tracker and source code:**
+https://github.com/python-trio/pytest-trio
-Pytest plugin for trio
+**License:** MIT or Apache 2, your choice.
-License: Your choice of MIT or Apache License 2.0
+**Code of conduct:** Contributors are requested to follow our `code of
+conduct
+`__
+in all project spaces.
diff --git a/docs/source/history.rst b/docs/source/history.rst
index 38c7930..2f8fce7 100644
--- a/docs/source/history.rst
+++ b/docs/source/history.rst
@@ -5,7 +5,27 @@ Release history
.. towncrier release notes start
-Pytest_Trio 0.4.2 (2018-06-29)
+pytest-trio 0.5.0 (????-??-??)
+------------------------------
+
+This is a major release, including a rewrite of large portions of the
+internals. We believe it should be backwards compatible with existing
+projects, but major new features include:
+
+* "trio mode": no more writing ``@pytest.mark.trio`` everywhere!
+* it's now safe to use nurseries inside fixtures (`#55
+ `__)
+* new ``@trio_fixture`` decorator to explicitly mark a fixture as a
+ trio fixture
+* a number of easy-to-make mistakes are now caught and raise
+ informative errors
+* the :data:`nursery` fixture is now 87% more magical
+
+For more details, see the manual. Oh right, speaking of which: we
+finally have a manual! You should read it.
+
+
+pytest-trio 0.4.2 (2018-06-29)
------------------------------
Features
@@ -16,20 +36,20 @@ Features
using Trio. (`#42 `__)
-Pytest_Trio 0.4.1 (2018-04-14)
+pytest-trio 0.4.1 (2018-04-14)
------------------------------
No significant changes.
-Pytest_Trio 0.4.0 (2018-04-14)
+pytest-trio 0.4.0 (2018-04-14)
------------------------------
- Fix compatibility with trio 0.4.0 (`#25
`__)
-Pytest_Trio 0.3.0 (2018-01-03)
+pytest-trio 0.3.0 (2018-01-03)
------------------------------
Features
@@ -39,7 +59,7 @@ Features
`__)
-Pytest_Trio 0.2.0 (2017-12-15)
+pytest-trio 0.2.0 (2017-12-15)
------------------------------
- Heavy improvements, add async yield fixture, fix bugs, add tests etc. (`#17
@@ -53,14 +73,14 @@ Deprecations and Removals
`__)
-Pytest_Trio 0.1.1 (2017-12-08)
+pytest-trio 0.1.1 (2017-12-08)
------------------------------
Disable intersphinx for trio (cause crash in CI for the moment due to 404
in readthedoc).
-Pytest_Trio 0.1.0 (2017-12-08)
+pytest-trio 0.1.0 (2017-12-08)
------------------------------
Initial release.
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 118c45b..fd29f82 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -8,9 +8,64 @@
pytest-trio: Pytest plugin for trio
===================================
+This is a pytest plugin to help you test projects that use `Trio
+`__, a friendly library for concurrency
+and async I/O in Python. Features include:
+
+* Async tests without the boilerplate: just write ``async def
+ test_whatever(): ...``.
+
+* Useful fixtures included: use :data:`autojump_clock` for easy
+ testing of code with timeouts, or :data:`nursery` to easily set up
+ background tasks.
+
+* Write your own async fixtures: set up an async database connection
+ or start a server inside a fixture, and then use it in your tests.
+
+* If you have multiple async fixtures, pytest-trio will even do
+ setup/teardown concurrently whenever possible. (Though honestly,
+ we're not sure whether this is a good idea or not and might remove
+ it in the future. If it makes your tests harder to debug, or
+ conversely provides you with big speedups, `please let us know
+ `__.)
+
+* Integration with the fabulous `Hypothesis
+ `__ library, so your async tests can use
+ property-based testing: just use ``@given`` like you're used to.
+
+* Support for testing projects that use Trio exclusively and want to
+ use pytest-trio everywhere, and also for testing projects that
+ support multiple async libraries and only want to enable
+ pytest-trio's features for a subset of their test suite.
+
+
+Vital statistics
+================
+
+* Install: ``pip install pytest-trio``
+
+* Documentation: https://pytest-trio.readthedocs.io
+
+* Issue tracker, source code: https://github.com/python-trio/pytest-trio
+
+* License: MIT or Apache 2, your choice
+
+* Contributor guide: https://trio.readthedocs.io/en/latest/contributing.html
+
+* Code of conduct: Contributors are requested to follow our `code of
+ conduct
+ `__ in
+ all project spaces.
+
.. toctree::
:maxdepth: 2
+ quickstart.rst
+ reference.rst
+
+.. toctree::
+ :maxdepth: 1
+
history.rst
====================
diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst
new file mode 100644
index 0000000..0c6f918
--- /dev/null
+++ b/docs/source/quickstart.rst
@@ -0,0 +1,422 @@
+Quickstart
+==========
+
+Enabling Trio mode and running your first async tests
+-----------------------------------------------------
+
+.. note:: If you used `cookiecutter-trio
+ `__ to set up
+ your project, then pytest-trio and Trio mode are already
+ configured! You can write ``async def test_whatever(): ...`` and it
+ should just work. Feel free to skip to the next section.
+
+Let's make a temporary directory to work in, and write two trivial
+tests: one that we expect should pass, and one that we expect should
+fail::
+
+ # test_example.py
+ import trio
+
+ async def test_sleep():
+ start_time = trio.current_time()
+ await trio.sleep(1)
+ end_time = trio.current_time()
+ assert end_time - start_time >= 1
+
+ async def test_should_fail():
+ assert False
+
+If we run this under pytest normally, then we get a strange result:
+
+.. code-block:: none
+
+ $ pytest test_example.py
+
+ ======================== test session starts =========================
+ platform linux -- Python 3.6.5, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
+ rootdir: /tmp, inifile:
+ collected 2 items
+
+ test_example.py .. [100%]
+
+ ========================== warnings summary ==========================
+ test_example.py::test_sleep
+ .../_pytest/python.py:196: RuntimeWarning: coroutine 'test_sleep' was never awaited
+ testfunction(**testargs)
+
+ test_example.py::test_should_fail
+ .../_pytest/python.py:196: RuntimeWarning: coroutine 'test_should_fail' was never awaited
+ testfunction(**testargs)
+
+ -- Docs: http://doc.pytest.org/en/latest/warnings.html
+ ================ 2 passed, 2 warnings in 0.02 seconds ================
+
+So ``test_sleep`` passed, which is what we expected... but
+``test_should_fail`` also passes, which is strange. And it says that
+the whole test run completed in 0.02 seconds, which is weird, because
+``test_sleep`` should have taken at least second to run. And then
+there are these strange warnings at the bottom... what's going on
+here?
+
+The problem is that our tests are async, and pytest doesn't know what
+to do with it. So it basically skips running them entirely, and then
+reports them as passed. This is not very helpful! If you see warnings
+like this, or if your tests seem to pass but your coverage reports
+claim that they weren't run at all, then this might be the problem.
+
+Here's the fix:
+
+1. Install pytest-trio: ``pip install pytest-trio``
+
+2. In your project root, create a file called ``pytest.ini`` with
+ contents:
+
+ .. code-block:: none
+
+ [pytest]
+ trio_mode = true
+
+And we're done! Let's try running pytest again:
+
+.. code-block:: none
+
+ $ pip install pytest-trio
+
+ $ cat <pytest.ini
+ [pytest]
+ trio_mode = true
+ EOF
+
+ $ pytest test_example.py
+ ======================== test session starts =========================
+ platform linux -- Python 3.6.5, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
+ rootdir: /tmp, inifile: pytest.ini
+ plugins: trio-0.4.2
+ collected 2 items
+
+ test_example.py .F [100%]
+
+ ============================== FAILURES ==============================
+ __________________________ test_should_fail __________________________
+
+ async def test_should_fail():
+ > assert False
+ E assert False
+
+ test_example.py:7: AssertionError
+ ================= 1 failed, 1 passed in 1.05 seconds =================
+
+Notice that now it says ``plugins: trio``, which means that
+pytest-trio is installed, and the results make sense: the good test
+passed, the bad test failed, no warnings, and it took just over 1
+second, like we'd expect.
+
+
+Trio's magic autojump clock
+---------------------------
+
+Tests involving time are often slow and flaky. But we can
+fix that. Just add the ``autojump_clock`` fixture to your test, and
+it will run in a mode where Trio's clock is virtualized and
+deterministic. Essentially, the clock doesn't move, except that whenever all
+tasks are blocked waiting, it jumps forward until the next time when
+something will happen::
+
+ # Notice the 'autojump_clock' argument: that's all it takes!
+ async def test_sleep_efficiently_and_reliably(autojump_clock):
+ start_time = trio.current_time()
+ await trio.sleep(1)
+ end_time = trio.current_time()
+ assert start_time - end_time == 1
+
+In the version of this test we saw before that used real time, at the
+end we had to use a ``>=`` comparison, in order to account for
+scheduler jitter and so forth. If there were a bug that caused
+:func:`trio.sleep` to take 10 seconds, our test wouldn't have noticed.
+But now we're using virtual time, so the call to ``await
+trio.sleep(1)`` takes *exactly* 1 virtual second, and the ``==`` test
+will pass every time. Before, we had to wait around for the test to
+complete; now, it completes essentially instantaneously. (Try it!)
+And, while here our example is super simple, it's integration with
+Trio's core scheduling logic allows this to work for arbitrarily
+complex programs (as long as they aren't interacting with the outside
+world).
+
+
+Async fixtures
+--------------
+
+We can write async fixtures::
+
+ @pytest.fixture
+ async def db_connection():
+ return await some_async_db_library.connect(...)
+
+ async def test_example(db_connection):
+ await db_connection.execute("SELECT * FROM ...")
+
+If you need to run teardown code, you can use ``yield``, just like a
+regular pytest fixture::
+
+ # DB connection that wraps each test in a transaction and rolls it
+ # back afterwards
+ @pytest.fixture
+ async def rollback_db_connection():
+ # Setup code
+ connection = await some_async_db_library.connect(...)
+ await connection.execute("START TRANSACTION")
+
+ # The value of this fixture
+ yield connection
+
+ # Teardown code, executed after the test is done
+ await connection.execute("ROLLBACK")
+
+If you need to support Python 3.5, which doesn't allow ``yield``
+inside an ``async def`` function, then you can define async fixtures
+using the `async_generator
+`__
+library – just make sure to put the ``@pytest.fixture`` *above* the
+``@async_generator``.
+
+
+.. _server-fixture-example:
+
+Running a background server from a fixture
+------------------------------------------
+
+Here's some code to implement an echo server. It's supposed to take in
+arbitrary data, and then send it back out again::
+
+ async def echo_server_handler(stream):
+ while True:
+ data = await stream.receive_some(1000)
+ if not data:
+ break
+ await stream.send_all(data)
+
+ # Usage: await trio.serve_tcp(echo_server_handler, ...)
+
+Now we need to test it, to make sure it's working correctly. In fact,
+since this is such complicated and sophisticated code, we're going to
+write lots of tests for it. And they'll all follow the same basic
+pattern: we'll start the echo server running in a background task,
+then connect to it, send it some test data, and see how it responds.
+Here's a first attempt::
+
+ # Let's cross our fingers and hope no-one else is using this port...
+ PORT = 14923
+
+ # Don't copy this -- we can do better
+ async def test_attempt_1():
+ async with trio.open_nursery() as nursery:
+ # Start server running in the background
+ nursery.start_soon(
+ partial(trio.serve_tcp, echo_server_handler, port=PORT)
+ )
+
+ # Connect to the server.
+ echo_client = await trio.open_tcp_stream("127.0.0.1", PORT)
+ # Send some test data, and check that it gets echoed back
+ async with echo_client:
+ for test_byte in [b"a", b"b", b"c"]:
+ await echo_client.send_all(test_byte)
+ assert await echo_client.receive_some(1) == test_byte
+
+This will mostly work, but it has a few problems. The most obvious one
+is that when we run it, even if everything works perfectly, it will
+hang at the end of the test – we never shut down the server, so the
+nursery block will wait forever for it to exit.
+
+To avoid this, we should cancel the nursery at the end of the test:
+
+.. code-block:: python3
+ :emphasize-lines: 7,20,21
+
+ # Let's cross our fingers and hope no-one else is using this port...
+ PORT = 14923
+
+ # Don't copy this -- we can do better
+ async def test_attempt_2():
+ async with trio.open_nursery() as nursery:
+ try:
+ # Start server running in the background
+ nursery.start_soon(
+ partial(trio.serve_tcp, echo_server_handler, port=PORT)
+ )
+
+ # Connect to the server.
+ echo_client = await trio.open_tcp_stream("127.0.0.1", PORT)
+ # Send some test data, and check that it gets echoed back
+ async with echo_client:
+ for test_byte in [b"a", b"b", b"c"]:
+ await echo_client.send_all(test_byte)
+ assert await echo_client.receive_some(1) == test_byte
+ finally:
+ nursery.cancel_scope.cancel()
+
+In fact, this pattern is *so* common, that pytest-trio provides a
+handy :data:`nursery` fixture to let you skip the boilerplate. Just
+add ``nursery`` to your test function arguments, and pytest-trio will
+open a nursery, pass it in to your function, and then cancel it for
+you afterwards:
+
+.. code-block:: python3
+ :emphasize-lines: 5
+
+ # Let's cross our fingers and hope no-one else is using this port...
+ PORT = 14923
+
+ # Don't copy this -- we can do better
+ async def test_attempt_3(nursery):
+ # Start server running in the background
+ nursery.start_soon(
+ partial(trio.serve_tcp, echo_server_handler, port=PORT)
+ )
+
+ # Connect to the server.
+ echo_client = await trio.open_tcp_stream("127.0.0.1", PORT)
+ # Send some test data, and check that it gets echoed back
+ async with echo_client:
+ for test_byte in [b"a", b"b", b"c"]:
+ await echo_client.send_all(test_byte)
+ assert await echo_client.receive_some(1) == test_byte
+
+Next problem: we have a race condition. We spawn a background task to
+call ``serve_tcp``, and then immediately try to connect to that
+server. Sometimes this will work fine. But it takes a little while for
+the server to start up and be ready to accept connections – so other
+times, randomly, our connection attempt will happen too quickly, and
+error out. After all – ``nursery.start_soon`` only promises that the
+task will be started *soon*, not that it's actually happened. So this
+test will be flaky, and flaky tests are the worst.
+
+Fortunately, Trio makes this easy to solve, by switching to using
+``await nursery.start(...)``. You can `read its docs for full details
+`__,
+but basically the idea is that both ``nursery.start_soon(...)`` and
+``await nursery.start(...)`` create background tasks, but only
+``start`` waits for the new task to finish getting itself set up. This
+requires some cooperation from the background task: it has to notify
+``nursery.start`` when it's ready. Fortunately, :func:`trio.serve_tcp`
+already knows how to cooperate with ``nursery.start``, so we can
+write:
+
+.. code-block:: python3
+ :emphasize-lines: 6-10
+
+ # Let's cross our fingers and hope no-one else is using this port...
+ PORT = 14923
+
+ # Don't copy this -- we can do better
+ async def test_attempt_4(nursery):
+ # Start server running in the background
+ # AND wait for it to finish starting up before continuing
+ await nursery.start(
+ partial(trio.serve_tcp, echo_server_handler, port=PORT)
+ )
+
+ # Connect to the server
+ echo_client = await trio.open_tcp_stream("127.0.0.1", PORT)
+ async with echo_client:
+ for test_byte in [b"a", b"b", b"c"]:
+ await echo_client.send_all(test_byte)
+ assert await echo_client.receive_some(1) == test_byte
+
+That solves our race condition. Next issue: hardcoding the port number
+like this is a bad idea, because port numbers are a machine-wide
+resource, so if we're unlucky some other program might already be
+using it. What we really want to do is to tell :func:`~trio.serve_tcp`
+to pick a random port that no-one else is using. It turns out that
+this is easy: if you request port 0, then the operating system will
+pick an unused one for you automatically. Problem solved!
+
+But wait... if the operating system is picking the port for us, how do
+we know figure out which one it picked, so we can connect to it later?
+
+Well, there's no way to predict the port ahead of time. But after
+:func:`~trio.serve_tcp` has opened a port, it can check and see what
+it got. So we need some way to pass this data back out of
+:func:`~trio.serve_tcp`. Fortunately, ``nursery.start`` handles this
+too: it lets the task pass out a piece of data after it's started. And
+it just so happens that what :func:`~trio.serve_tcp` passes out is a
+list of :class:`~trio.SocketListener` objects. And there's a handy
+function called :func:`trio.testing.open_stream_to_socket_listener`
+that can take a :class:`~trio.SocketListener` and make a connection to
+it.
+
+Putting it all together:
+
+.. code-block:: python3
+ :emphasize-lines: 1,8,13-16
+
+ from trio.testing import open_stream_to_socket_listener
+
+ # Don't copy this -- it finally works, but we can still do better!
+ async def test_attempt_5(nursery):
+ # Start server running in the background
+ # AND wait for it to finish starting up before continuing
+ # AND find out where it's actually listening
+ listeners = await nursery.start(
+ partial(trio.serve_tcp, echo_server_handler, port=0)
+ )
+
+ # Connect to the server.
+ # There might be multiple listeners (example: IPv4 and
+ # IPv6), but we don't care which one we connect to, so we
+ # just use the first.
+ echo_client = await open_stream_to_socket_listener(listeners[0])
+ async with echo_client:
+ for test_byte in [b"a", b"b", b"c"]:
+ await echo_client.send_all(test_byte)
+ assert await echo_client.receive_some(1) == test_byte
+
+Now, this works – but there's still a lot of boilerplate. Remember, we
+need to write lots of tests for this server, and we don't want to have
+to copy-paste all that stuff into every test. Let's factor out the
+setup into a fixture::
+
+ @pytest.fixture
+ async def echo_client(nursery):
+ listeners = await nursery.start(
+ partial(trio.serve_tcp, echo_server_handler, port=0)
+ )
+ echo_client = await open_stream_to_socket_listener(listeners[0])
+ async with echo_client:
+ yield echo_client
+
+And now in tests, all we have to do is request the ``echo_client``
+fixture, and we get a background server and a client stream connected
+to it. So here's our complete, final version::
+
+ # Final version -- copy this!
+ from functools import partial
+ import pytest
+ import trio
+ from trio.testing import open_stream_to_socket_listener
+
+ # The code being tested:
+ async def echo_server_handler(stream):
+ while True:
+ data = await stream.receive_some(1000)
+ if not data:
+ break
+ await stream.send_all(data)
+
+ # The fixture:
+ @pytest.fixture
+ async def echo_client(nursery):
+ listeners = await nursery.start(
+ partial(trio.serve_tcp, echo_server_handler, port=0)
+ )
+ echo_client = await open_stream_to_socket_listener(listeners[0])
+ async with echo_client:
+ yield echo_client
+
+ # A test using the fixture:
+ async def test_final(echo_client):
+ for test_byte in [b"a", b"b", b"c"]:
+ await echo_client.send_all(test_byte)
+ assert await echo_client.receive_some(1) == test_byte
+
+No hangs, no race conditions, simple, clean, and reusable.
diff --git a/docs/source/reference.rst b/docs/source/reference.rst
new file mode 100644
index 0000000..6a56539
--- /dev/null
+++ b/docs/source/reference.rst
@@ -0,0 +1,275 @@
+Reference
+=========
+
+Trio mode
+---------
+
+Most users will want to enable "Trio mode". Without Trio mode:
+
+* Pytest-trio only handles tests that have been decorated with
+ ``@pytest.mark.trio``
+* Pytest-trio only handles fixtures if they're async *and* used by a
+ test that's decorated with ``@pytest.mark.trio``, or if they're
+ decorated with ``@pytest_trio.trio_fixture`` (instead of
+ ``@pytest.fixture``).
+
+When Trio mode is enabled, two extra things happen:
+
+* Async tests automatically have the ``trio`` mark added, so you don't
+ have to do it yourself.
+* Async fixtures using ``@pytest.fixture`` automatically get converted
+ to Trio fixtures. (The main effect of this is that it helps you
+ catch mistakes where a you use an async fixture with a non-async
+ test.)
+
+There are two ways to enable Trio mode.
+
+The first option is to **use a pytest configuration file**. The exact
+rules for how pytest finds configuration files are `a bit complicated
+`__, but you want to
+end up with something like:
+
+.. code-block:: ini
+
+ # pytest.ini
+ [pytest]
+ trio_mode = true
+
+The second option is **use a conftest.py file**. Inside your tests
+directory, create a file called ``conftest.py``, with the following
+contents::
+
+ # conftest.py
+ from pytest_trio.enable_trio_mode import *
+
+This does exactly the same thing as setting ``trio_mode = true`` in
+``pytest.ini``, except for two things:
+
+* Some people like to ship their tests as part of their library, so
+ they (or their users) can test the final installed software by
+ running ``pytest --pyargs PACKAGENAME``. In this mode,
+ ``pytest.ini`` files don't work, but ``conftest.py`` files do.
+
+* Enabling Trio mode in ``pytest.ini`` always enables it globally for
+ your entire testsuite. Enabling it in ``conftest.py`` only enables
+ it for test files that are in the same directory as the
+ ``conftest.py``, or its subdirectories.
+
+If you have software that uses multiple async libraries, then you can
+use ``conftest.py`` to enable Trio mode for just the part of your
+testsuite that uses Trio; or, if you need even finer-grained control,
+you can leave Trio mode disabled and use ``@pytest.mark.trio``
+explicitly on all your Trio tests.
+
+
+Trio fixtures
+-------------
+
+Normally, pytest runs fixture code before starting the test, and
+teardown code afterwards. For technical reasons, we can't wrap this
+whole process in :func:`trio.run` – only the test itself. As a
+workaround, pytest-trio introduces the concept of a "Trio fixture",
+which acts like a normal fixture for most purposes, but actually does
+the setup and teardown inside the test's call to :func:`trio.run`.
+
+The following fixtures are treated as Trio fixtures:
+
+* Any function decorated with ``@pytest_trio.trio_fixture``.
+* Any async function decorated with ``@pytest.fixture``, *if*
+ Trio mode is enabled *or* this fixture is being requested by a Trio
+ test.
+* Any fixture which depends on a Trio fixture.
+
+The most notable difference between regular fixtures and Trio fixtures
+is that regular fixtures can't use Trio APIs, but Trio fixtures can.
+Most of the time you don't need to worry about this, because you
+normally only call Trio APIs from async functions, and when Trio mode
+is enabled, all async fixtures are automatically Trio fixtures.
+However, if for some reason you do want to use Trio APIs from a
+synchronous fixture, then you'll have to use
+``@pytest_trio.trio_fixture``::
+
+ # This fixture is not very useful
+ # But it is an example where @pytest.fixture doesn't work
+ @pytest_trio.trio_fixture
+ def trio_time():
+ return trio.current_time()
+
+Only Trio tests can use Trio fixtures. If you have a regular
+(synchronous) test that tries to use a Trio fixture, then that's an
+error.
+
+And finally, regular fixtures can be `scoped to the test, class,
+module, or session
+`__,
+but Trio fixtures **must be test scoped**. Class, module, and session
+scope are not supported.
+
+
+Concurrent setup/teardown
+-------------------------
+
+If your test uses multiple fixtures, then for speed, pytest-trio will
+try to run their setup and teardown code concurrently whenever this is
+possible while respecting the fixture dependencies.
+
+Here's an example, where a test depends on ``fix_b`` and ``fix_c``,
+and these both depend on ``fix_a``::
+
+ @trio_fixture
+ def fix_a():
+ ...
+
+ @trio_fixture
+ def fix_b(fix_a):
+ ...
+
+ @trio_fixture
+ def fix_c(fix_a):
+ ...
+
+ @pytest.mark.trio
+ async def test_example(fix_b, fix_c):
+ ...
+
+When running ``test_example``, pytest-trio will perform the following
+sequence of actions:
+
+1. Set up ``fix_a``
+2. Set up ``fix_b`` and ``fix_c``, concurrently.
+3. Run the test.
+4. Tear down ``fix_b`` and ``fix_c``, concurrently.
+5. Tear down ``fix_a``.
+
+We're `seeking feedback
+`__ on whether
+this feature's benefits outweigh its negatives.
+
+
+Handling of ContextVars
+-----------------------
+
+The :mod:`contextvars` module lets you create
+:class:`~contextvars.ContextVar` objects to represent task-local
+variables. Normally, in Trio, each task gets its own
+:class:`~contextvars.Context`, so that changes to
+:class:`~contextvars.ContextVar` objects are only visible inside the
+task that performs them. But pytest-trio overrides this, and for each
+test it uses a single :class:`~contextvars.Context` which is shared by
+all fixtures and the test function itself.
+
+The benefit of this is that you can set
+:class:`~contextvars.ContextVar` values inside a fixture, and your
+settings will be visible in dependent fixtures and the test itself.
+For example, `trio-asyncio `__
+uses a :class:`~contextvars.ContextVar` to hold the current asyncio
+loop object, so this lets you open a loop inside a fixture and then
+use it inside other fixtures or the test itself.
+
+The downside is that if two fixtures are run concurrently (see
+previous section), and both mutate the same
+:class:`~contextvars.ContextVar`, then there will be a race condition
+and the the final value will be unpredictable. If you make one fixture
+depend on the other, then this will force an ordering and make the
+final value predictable again.
+
+
+Built-in fixtures
+-----------------
+
+These fixtures are automatically available to any code using
+pytest-trio.
+
+.. data:: autojump_clock
+
+ A :class:`trio.testing.MockClock`, configured with ``rate=0,
+ autojump_threshold=0``.
+
+.. data:: mock_clock
+
+ A :class:`trio.testing.MockClock`, with its default configuration
+ (``rate=0, autojump_threshold=inf``).
+
+What makes these particularly useful is that whenever pytest-trio runs
+a test, it checks the fixtures to see if one of them is a
+:class:`trio.abc.Clock` object. If so, it passes that object to
+:func:`trio.run`. So if your test requests one of these fixtures, it
+automatically uses that clock.
+
+If you implement your own :class:`~trio.abc.Clock`, and implement a
+fixture that returns it, then it will work the same way.
+
+Of course, like any pytest fixture, you also get the actual object
+available. For example, you can call
+:meth:`~trio.testing.MockClock.jump`::
+
+ async def test_time_travel(mock_clock):
+ assert trio.current_time() == 0
+ mock_clock.jump(10)
+ assert trio.current_time() == 10
+
+.. data:: nursery
+
+ A nursery created and managed by pytest-trio itself, which
+ surrounds the test/fixture that requested it, and is automatically
+ cancelled after the test/fixture completes. Basically, these are
+ equivalent::
+
+ # Boring way
+ async def test_with_background_task():
+ async with trio.open_nursery() as nursery:
+ try:
+ ...
+ finally:
+ nursery.cancel_scope.cancel()
+
+ # Fancy way
+ async def test_with_background_task(nursery):
+ ...
+
+ For a fixture, the cancellation always happens after the fixture
+ completes its teardown phase. (Or if it doesn't have a teardown
+ phase, then the cancellation happens after the teardown phase
+ *would* have happened.)
+
+ This fixture is even more magical than most pytest fixtures,
+ because if it gets requested several times within the same test,
+ then it creates multiple nurseries, one for each fixture/test that
+ requested it.
+
+ See :ref:`server-fixture-example` for an example of how this can be
+ used.
+
+
+Integration with the Hypothesis library
+---------------------------------------
+
+There isn't too much to say here, since the obvious thing just works::
+
+ from hypothesis import given
+ import hypothesis.strategies as st
+
+ @given(st.binary())
+ async def test_trio_and_hypothesis(data):
+ ...
+
+Under the hood, this requires some coordination between Hypothesis and
+pytest-trio. Hypothesis runs your test multiple times with different
+examples of random data. For each example, pytest-trio calls
+:func:`trio.run` again (so you get a fresh clean Trio environment),
+sets up any Trio fixtures, runs the actual test, and then tears down
+any Trio fixtures. Notice that this is a bit different than regular
+pytest fixtures, which are `instantiated once and then re-used for all
+`__. Most of the time
+this shouldn't matter (and `is probably what you want anyway
+`__), but in
+some unusual cases it could surprise you. And this only applies to
+Trio fixtures – if a Trio test uses a mix of regular fixtures and Trio
+fixtures, then the regular fixtures will be reused, while the Trio
+fixtures will be repeatedly reinstantiated.
+
+Also, pytest-trio only handles ``@given``\-based tests. If you want to
+write `stateful tests
+`__ for
+Trio-based libraries, then check out `hypothesis-trio
+`__.
diff --git a/pyproject.toml b/pyproject.toml
index 77448c7..407fb8b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,5 +2,6 @@
package = "pytest_trio"
filename = "docs/source/history.rst"
directory = "newsfragments"
+title_format = "pytest-trio {version} ({project_date})"
underlines = ["-", "~", "^"]
issue_format = "`#{issue} `__"