Patterns of Use#
Several commons patterns of use for Sybil are covered here.
Documentation and source examples in Restructured Text#
If your project looks like this:
├─docs/
│ ├─conf.py
│ └─index.rst
├─src/
│ └─myproj/
│ └─__init__.py
├─conftest.py
├─pytest.ini
└─setup.py
And if your documentation looks like this:
My Project
==========
.. invisible-code-block: python
import myproj
myproj.SEED = 0.3
This project helps you bar your foo!
>>> from myproj import foo
>>> foo('baz')
'baz bar bar bar'
With your examples in source code looking like this:
"""
This package foo's stuff so it bars.
:data:`SEED` is normally random, but if you like you
can set it as follows:
.. code-block:: python
import myproj
myproj.SEED = 0.2
"""
import random
SEED: float = random.random()
def foo(text: str):
"""
Put some ``bar`` on your ``foo``!
>>> foo('stuff')
'stuff bar bar'
"""
return text+int(SEED*10)*' bar'
Then the following configuration in a conftest.py
will ensure all
your examples are correct:
import pytest
from sybil import Sybil
from sybil.parsers.rest import DocTestParser, PythonCodeBlockParser
@pytest.fixture(scope='session')
def keep_seed():
import myproj
seed = myproj.SEED
yield
myproj.SEED = seed
pytest_collect_file = Sybil(
parsers=[
DocTestParser(),
PythonCodeBlockParser(),
],
patterns=['*.rst', '*.py'],
fixtures=['keep_seed']
).pytest()
Documentation in MyST and source examples in Restructured Text#
If your project looks like this:
├─docs/
│ ├─conf.py
│ └─index.md
├─src/
│ └─myproj/
│ └─__init__.py
├─conftest.py
├─pytest.ini
└─setup.py
And if your documentation looks like this:
My Project
####
% invisible-code-block: python
%
% import myproj
% myproj.SEED = 0.3
This project helps you bar your foo!
```{doctest}
>>> from myproj import foo
>>> foo('baz')
'baz bar bar bar'
```
With your examples in source code looking like this:
"""
This package foo's stuff so it bars.
:data:`SEED` is normally random, but if you like you
can set it as follows:
.. code-block:: python
import myproj
myproj.SEED = 0.2
"""
import random
SEED: float = random.random()
def foo(text: str):
"""
Put some ``bar`` on your ``foo``!
>>> foo('stuff')
'stuff bar bar'
"""
return text+int(SEED*10)*' bar'
Then the following configuration in a conftest.py
will ensure all
your examples are correct:
import pytest
from sybil import Sybil
from sybil.parsers.myst import (
DocTestDirectiveParser as MarkdownDocTestParser,
PythonCodeBlockParser as MarkdownPythonCodeBlockParser
)
from sybil.parsers.rest import (
DocTestParser as ReSTDocTestParser,
PythonCodeBlockParser as ReSTPythonCodeBlockParser
)
@pytest.fixture(scope='session')
def keep_seed():
import myproj
seed = myproj.SEED
yield
myproj.SEED = seed
markdown_examples = Sybil(
parsers=[
MarkdownDocTestParser(),
MarkdownPythonCodeBlockParser(),
],
patterns=['*.md'],
fixtures=['keep_seed']
)
rest_examples = Sybil(
parsers=[
ReSTDocTestParser(),
ReSTPythonCodeBlockParser(),
],
patterns=['*.py'],
fixtures=['keep_seed']
)
pytest_collect_file = (markdown_examples+rest_examples).pytest()
Migrating from sphinx.ext.doctest#
Sybil currently has partial support for
sphinx.ext.doctest.
The list below shows how to approach migrating or supporting the various
directives from sphinx.ext.doctest
. Adding further support won’t be hard,
so if anything is missing that’s holding you back, please open an issue on GitHub.
After that, it’s mainly left to stop running make doctest
!
testsetup
can be replaced with invisible-code-block.testcleanup
can be replaced with invisible-code-block.doctest
is supported using theDocTestDirectiveParser
as described in the doctest section. Some of the options aren’t supported, but their behaviour can be replaced by preceding thedoctest
with a skip directive.testcode
andtestoutput
would need parsers and evaluators to be written, however, they could probably just be replaced with a doctest block.groups
aren’t supported, but you can achieve test isolation using clear-namespace.