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!
testsetupcan be replaced with invisible-code-block.testcleanupcan be replaced with invisible-code-block.doctestis supported using theDocTestDirectiveParseras described in the doctest section. Some of the options aren’t supported, but their behaviour can be replaced by preceding thedoctestwith a skip directive.testcodeandtestoutputwould need parsers and evaluators to be written, however, they could probably just be replaced with a doctest block.groupsaren’t supported, but you can achieve test isolation using clear-namespace.