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!