Skip to content

Commit

Permalink
feat(docs): add documentation (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
lengau authored Jan 19, 2025
1 parent 2533a52 commit a53facc
Show file tree
Hide file tree
Showing 17 changed files with 971 additions and 156 deletions.
3 changes: 3 additions & 0 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@
],
"lockFileMaintenance": {
"enabled": true,
},
"pre-commit": {
"enabled": true
}
}
8 changes: 7 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ repos:
- id: mixed-line-ending
- repo: https://github.com/astral-sh/ruff-pre-commit
# renovate: datasource=pypi;depName=ruff
rev: "v0.6.2"
rev: "v0.9.2"
hooks:
- id: ruff-format
- id: ruff
Expand All @@ -24,3 +24,9 @@ repos:
rev: "v1.35.1"
hooks:
- id: yamllint
- repo: https://github.com/rstcheck/rstcheck
rev: v6.2.4
hooks:
- id: rstcheck
additional_dependencies:
- rstcheck[toml,sphinx]
7 changes: 3 additions & 4 deletions HACKING.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
*******
HACKING
*******
=======

To develop on pytest-time, download `uv <https://docs.astral.sh/uv/>`_, either from
official sources or from `the snap <https://snapcraft.io/astral-uv>`_. You can then
use ``uv sync`` to set up your venv.
official sources or from `the snap <https://snapcraft.io/astral-uv>`_. You can then use
``uv sync`` to set up your venv.

Testing
-------
Expand Down
15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,20 @@ help: ## Show this help.
format:
ruff format .
ruff check --fix .
uv run --group lint docstrfmt .
uv run --group lint codespell --toml pyproject.toml --write-changes .

.PHONY: lint-ruff
lint-ruff:
ruff format --check --diff .
ruff check .

.PHONY: lint-docs
lint-docs:
uv run --group lint docstrfmt --check .

.PHONY: lint
lint: lint-ruff lint-types
lint: lint-ruff lint-types lint-docs
uv run --group lint codespell --toml pyproject.toml
uv run --group lint yamllint .
uv run --group lint rstcheck -r .
Expand All @@ -40,6 +45,14 @@ test:
test-oldest:
uv run --isolated --frozen --resolution=lowest --python-preference=only-system pytest

.PHONY: docs
docs:
make -C docs html

.PHONY: docs-auto
docs-auto: ## Auto-build docs
make -C docs auto

.PHONY: install-test-deps
install-test-deps:
ifneq ($(shell which apt-get),)
Expand Down
118 changes: 2 additions & 116 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,122 +1,8 @@
pytest-time
===========

The pytest-time plugin extends pytest to control ``time`` — the built-in Python
module, not the concept within the universe.
The pytest-time plugin extends pytest to control ``time`` — the built-in Python module,
not the concept within the universe.

.. image:: https://github.com/lengau/pytest-time/actions/workflows/tests.yaml/badge.svg
:target: https://github.com/lengau/pytest-time/actions/workflows/tests.yaml

Fixtures
--------

Pytest-time offers several fixtures for use in your projects, depending on your particular needs.

Instant Sleep
~~~~~~~~~~~~~

The ``instant_sleep`` fixture is the most basic wrapper and is designed to be used at any scope. It monkeypatches the built-in ``time`` module to be chronologically consistent while not actually sleeping when running ``time.sleep``. This includes modifying the behaviour of ``time.time()``, ``time.monotonic()`` and their nanosecond counterparts to include the additional delay expected after sleeping.

A basic use of ``instant_sleep`` is shown below:

.. code:: python
import time
import pytest
@pytest.mark.parametrize("sleep_time", [1, 10, 100])
@pytest.mark.usefixtures("instant_sleep")
def test_instant_sleep(sleep_time):
start_time = time.time()
start_monotonic = time.monotonic()
time.sleep(sleep_time)
assert time.time() >= start_time + sleep_time
assert time.monotonic() >= start_monotonic + sleep_time
This code will behave almost identically with and without the ``instant_sleep`` fixture in use. To demonstrate, let's time this file with the fixture enabled...

.. code:: text
$ time pytest test_instant_sleep.py
=========== test session starts ===========
platform linux -- Python 3.11.4, pytest-7.3.1, pluggy-1.0.0
rootdir: /home/lengau/Projects/pytest-time
configfile: pyproject.toml
plugins: check-2.1.5, mock-3.10.0, hypothesis-6.78.2, time-0.2.1.dev3+ga0d3b98.d20230624, cov-4.1.0
collected 3 items
test_instant_sleep.py ... [100%]
=========== 3 passed in 0.01s ===========
real 0m0.276s
user 0m0.240s
sys 0m0.025s
and disabled:

.. code:: text
$ time pytest test_instant_sleep_no_fixture.py
=========== test session starts ===========
platform linux -- Python 3.11.4, pytest-7.3.1, pluggy-1.0.0
rootdir: /home/lengau/Projects/pytest-time
configfile: pyproject.toml
plugins: check-2.1.5, mock-3.10.0, hypothesis-6.78.2, time-0.2.1.dev3+ga0d3b98.d20230624, cov-4.1.0
collected 3 items
test_instant_sleep_no_fixture.py ... [100%]
=========== 3 passed in 111.01s (0:01:51) ===========
real 1m51.354s
user 0m0.250s
sys 0m0.020s
The sleep is, for practical purposes, essentially instant. And yet, the ``time`` module still acts as though the appropriate time has passed.

Recording Time Calls
~~~~~~~~~~~~~~~~~~~~~

Pytest-time also provides ``mock_time``, a fixture that wraps several ``time`` functions in Mock objects but still runs the real calls. This is useful if you need to ensure that certain calls occurred, etc. The fixture will provide Mock objects for inspection in tests:

.. code:: python
import time
def test_mock_time(mock_time):
start_time = time.time()
start_monotonic = time.monotonic()
time.sleep(1) # Actually sleeps for a second
assert time.time() >= start_time + 1
assert time.monotonic() >= start_monotonic + 1
mock_time.sleep.assert_called_once_with(1)
assert len(mock_time.time.mock_calls) == 2
assert len(mock_time.monotonic.mock_calls) == 2
Mocking a Powernap
~~~~~~~~~~~~~~~~~~

The two above are combined for you in the ``mock_instant_sleep`` fixture. This fixture replaces the relevant ``time`` functions as in the ``instant_sleep`` fixture, but also provides mock wrappers around those functions, allowing for recording time.

.. code:: python
import time
def test_mock_instant_sleep(mock_instant_sleep):
start_time = time.time()
start_monotonic = time.monotonic()
time.sleep(86400) # Doesn't sleep
assert time.time() >= start_time + 86400
assert time.monotonic() >= start_monotonic + 86400
mock_instant_sleep.sleep.assert_called_once_with(86400)
assert len(mock_instant_sleep.time.mock_calls) == 2
assert len(mock_instant_sleep.monotonic.mock_calls) == 2
23 changes: 23 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

auto:
sphinx-autobuild --ignore '*.kate-swp' "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
39 changes: 39 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'pytest-time'
copyright = '2025, Alex Lowe'
author = 'Alex Lowe'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
]

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.kate-swp']



# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'furo'
html_static_path = ['_static']

# -- Options for intersphinx extension ---------------------------------------
# https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#configuration

intersphinx_mapping = {
'python': ('https://docs.python.org/3', None),
}
24 changes: 24 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
..
pytest-time documentation master file, created by
sphinx-quickstart on Sun Jan 19 17:56:54 2025.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
``pytest-time``
===============

.. toctree::
:maxdepth: 2
:caption: Contents:

reference/index

``pytest-time`` is a pytest extension for controlling Python's built-in
:external+python:doc:`time <library/time>` module.

Indices and tables
==================

- :ref:`genindex`
- :ref:`modindex`
- :ref:`search`
9 changes: 9 additions & 0 deletions docs/reference/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Reference
=========

.. toctree::
:maxdepth: 2

real_time
instant_sleep
mock_time
73 changes: 73 additions & 0 deletions docs/reference/instant_sleep.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
Instant sleep
=============

The ``instant_sleep`` fixture is the most basic wrapper and is designed to be used at
any scope. It monkeypatches the built-in ``time`` module to be chronologically
consistent while not actually sleeping when running ``time.sleep``. This includes
modifying the behaviour of ``time.time()``, ``time.monotonic()`` and their nanosecond
counterparts to include the additional delay expected after sleeping.

A basic use of ``instant_sleep`` is shown below:

.. code-block:: python
import time
import pytest
@pytest.mark.parametrize("sleep_time", [1, 10, 100])
@pytest.mark.usefixtures("instant_sleep")
def test_instant_sleep(sleep_time):
start_time = time.time()
start_monotonic = time.monotonic()
time.sleep(sleep_time)
assert time.time() >= start_time + sleep_time
assert time.monotonic() >= start_monotonic + sleep_time
This code will behave almost identically with and without the ``instant_sleep`` fixture
in use. To demonstrate, let's time this file with the fixture enabled...

.. code-block:: text
$ time pytest test_instant_sleep.py
=========== test session starts ===========
platform linux -- Python 3.11.4, pytest-7.3.1, pluggy-1.0.0
rootdir: /home/lengau/Projects/pytest-time
configfile: pyproject.toml
plugins: check-2.1.5, mock-3.10.0, hypothesis-6.78.2, time-0.2.1.dev3+ga0d3b98.d20230624, cov-4.1.0
collected 3 items
test_instant_sleep.py ... [100%]
=========== 3 passed in 0.01s ===========
real 0m0.276s
user 0m0.240s
sys 0m0.025s
and disabled:

.. code-block:: text
$ time pytest test_instant_sleep_no_fixture.py
=========== test session starts ===========
platform linux -- Python 3.11.4, pytest-7.3.1, pluggy-1.0.0
rootdir: /home/lengau/Projects/pytest-time
configfile: pyproject.toml
plugins: check-2.1.5, mock-3.10.0, hypothesis-6.78.2, time-0.2.1.dev3+ga0d3b98.d20230624, cov-4.1.0
collected 3 items
test_instant_sleep_no_fixture.py ... [100%]
=========== 3 passed in 111.01s (0:01:51) ===========
real 1m51.354s
user 0m0.250s
sys 0m0.020s
The sleep is, for practical purposes, essentially instant. And yet, the ``time`` module
still acts as though the appropriate time has passed.

.. autofunction:: pytest_time.instant_sleep
Loading

0 comments on commit a53facc

Please sign in to comment.