diff --git a/README.md b/README.md index 7633b2fd..e3bd5f61 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ ## Introduction + + Frequenz Channels is a *channels* implementation for Python. According to [Wikipedia](https://en.wikipedia.org/wiki/Channel_(programming)): @@ -20,14 +22,20 @@ Frequenz Channels are mostly designed after [Go channels](https://tour.golang.org/concurrency/2) but it also borrows ideas from [Rust channels](https://doc.rust-lang.org/book/ch16-02-message-passing.html). + + ## Supported Platforms + + The following platforms are officially supported (tested): - **Python:** 3.11 - **Operating System:** Ubuntu Linux 20.04 - **Architectures:** amd64, arm64 + + ## Quick Start We assume you are on a system with Python available. If that is not the case, diff --git a/docs/_scripts/macros.py b/docs/_scripts/macros.py index ca54f6a4..92373806 100644 --- a/docs/_scripts/macros.py +++ b/docs/_scripts/macros.py @@ -6,8 +6,11 @@ from typing import Any import markdown as md +from griffe import Object +from griffe.collections import ModulesCollection from markdown.extensions import toc from mkdocs_macros import plugin as macros +from mkdocstrings_handlers.python.handler import PythonHandler _CODE_ANNOTATION_MARKER: str = ( r'' @@ -77,5 +80,41 @@ def define_env(env: macros.MacrosPlugin) -> None: # https://squidfunk.github.io/mkdocs-material/reference/code-blocks/#adding-annotations env.variables["code_annotation_marker"] = _CODE_ANNOTATION_MARKER + python_handler = env.conf["plugins"]["mkdocstrings"].get_handler("python") + assert isinstance(python_handler, PythonHandler) + + def _get_docstring(symbol: str) -> str: + symbols = python_handler._modules_collection # pylint: disable=protected-access + assert isinstance(symbols, ModulesCollection) + + try: + obj = symbols[symbol] + except KeyError as exc: + raise ValueError(f"Symbol {symbol!r} not found.") from exc + assert isinstance(obj, Object) + + docstring = obj.docstring + if not docstring: + raise ValueError(f"Symbol {symbol!r} has no docstring.") + + return docstring.value + + # The decorator makes the function untyped + @env.macro # type: ignore[misc] + def docstring_summary(symbol: str) -> str: + """Get the summary of a Python symbol. + + Args: + symbol: The fully qualified name of the Python symbol to get the summary of. + + Returns: + The summary of the Python symbol. + """ + docstring = _get_docstring(symbol) + summary = docstring.splitlines(keepends=False)[0] + return python_handler.do_convert_markdown( + summary, heading_level=1, strip_paragraph=True + ) + # This hook needs to be done at the end of the `define_env` function. _hook_macros_plugin(env) diff --git a/docs/index.md b/docs/index.md index 8e2b2036..17590073 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,19 +2,19 @@ ## Introduction -Frequenz Channels is a *channels* implementation for Python. +{% + include-markdown "../README.md" + start="" + end="" +%} -According to [Wikipedia](https://en.wikipedia.org/wiki/Channel_(programming)): +## Supported Platforms -> A channel is a model for interprocess communication and synchronization via -> message passing. A message may be sent over a channel, and another process or -> thread is able to receive messages sent over a channel it has a reference to, -> as a stream. Different implementations of channels may be buffered or not, -> and either synchronous or asynchronous. - -Frequenz Channels are mostly designed after [Go -channels](https://tour.golang.org/concurrency/2) but it also borrows ideas from -[Rust channels](https://doc.rust-lang.org/book/ch16-02-message-passing.html). +{% + include-markdown "../README.md" + start="" + end="" +%} ## Installation @@ -77,5 +77,5 @@ $ python3 Python 3.11.4 (main, Jun 7 2023, 10:13:09) [GCC 12.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import frequenz.channels ->>> +>>> ``` diff --git a/mkdocs.yml b/mkdocs.yml index 6adfbe89..c184f59c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -24,9 +24,10 @@ theme: features: - content.code.annotate - content.code.copy + - navigation.expand + - navigation.footer - navigation.indexes - navigation.instant - - navigation.footer - navigation.tabs - navigation.top - navigation.tracking @@ -67,6 +68,8 @@ markdown_extensions: - attr_list - def_list - footnotes + - markdown_svgbob: + min_char_width: 0 - pymdownx.details - pymdownx.highlight: anchor_linenums: true @@ -90,6 +93,7 @@ plugins: - gen-files: scripts: - docs/_scripts/mkdocstrings_autoapi.py + - include-markdown - literate-nav: nav_file: SUMMARY.md - mike: @@ -129,3 +133,4 @@ plugins: watch: - "src" - CONTRIBUTING.md + - README.md diff --git a/pyproject.toml b/pyproject.toml index 279ccd25..7e433b22 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,33 +45,35 @@ dev-flake8 = [ ] dev-formatting = ["black == 23.10.1", "isort == 5.12.0"] dev-mkdocs = [ + "Markdown == 3.5.1", "black == 23.10.1", - "Markdown==3.5.1", + "frequenz-repo-config[lib] == 0.7.5", + "markdown-svgbob == 202112.1022", "mike == 2.0.0", "mkdocs-gen-files == 0.5.0", + "mkdocs-include-markdown-plugin == 6.0.4", "mkdocs-literate-nav == 0.6.1", - "mkdocs-material == 9.4.7", "mkdocs-macros-plugin == 1.0.5", + "mkdocs-material == 9.4.7", "mkdocstrings[python] == 0.23.0", - "frequenz-repo-config[lib] == 0.7.5", ] dev-mypy = [ - "mypy == 1.6.1", - "types-Markdown == 3.5.0.0", # For checking the noxfile, docs/ script, and tests "frequenz-channels[dev-mkdocs,dev-noxfile,dev-pytest]", + "mypy == 1.6.1", + "types-Markdown == 3.5.0.0", ] dev-noxfile = ["nox == 2023.4.22", "frequenz-repo-config[lib] == 0.7.5"] dev-pylint = [ - "pylint == 3.0.2", # For checking the noxfile, docs/ script, and tests "frequenz-channels[dev-mkdocs,dev-noxfile,dev-pytest]", + "pylint == 3.0.2", ] dev-pytest = [ - "pytest == 7.4.3", "async-solipsism == 0.5", - "hypothesis == 6.88.1", "frequenz-repo-config[extra-lint-examples] == 0.7.5", + "hypothesis == 6.88.1", + "pytest == 7.4.3", "pytest-asyncio == 0.21.1", "pytest-mock == 3.12.0", ] diff --git a/src/frequenz/channels/timer.py b/src/frequenz/channels/timer.py index 95594ec7..c4d65bc9 100644 --- a/src/frequenz/channels/timer.py +++ b/src/frequenz/channels/timer.py @@ -87,12 +87,16 @@ class TriggerAllMissed(MissedTickPolicy): `T5`, happens at 5.1 (0.1 seconds late), so it triggers immediately again. The seventh tick, `T6`, happens at 6.0, right on time. - ``` - 0 1 2 3 4 o 5 6 - o---------|-o-------|--o------|---------|--o------|o--------o-----> time +
+ ```bob + 0 1 2 3 4 T4 5 6 + *---------o-*-------o--*------o---------o--**-----o*--------*-----> time T0 T1 T2 T3 T5 T6 - T4 + + -o- "Expected ticks" + -*- "Delivered ticks" ``` +
""" def calculate_next_tick_time( @@ -134,11 +138,17 @@ class SkipMissedAndResync(MissedTickPolicy): `T5`, happens at 5.1 (0.1 seconds late), so it triggers immediately again. The seventh tick, `T6`, happens at 6.0, right on time. +
+ ```bob + 0 1 2 3 4 T4 5 6 + *---------o-*-------o--*------o---------o--*O-----o-*-------*-----> time + T0 T1 T2 T3 T5 T6 + + -o- "Expected ticks" + -*- "Delivered ticks" + -O- "Undelivered ticks (skipped)" ``` - 0 1 2 3 4 o 5 6 - o---------|-o-------|--o------|---------|--o------|o--------o-----> time - T0 T1 T2 T3 T5 T6 - ``` +
""" def calculate_next_tick_time( @@ -187,11 +197,17 @@ class SkipMissedAndDrift(MissedTickPolicy): so is right on time (no drift) and the same happens for tick `T6.3`, which triggers at 6.3 seconds. - ``` +
+ ```bob 0 1 2 3 4 5 6 - o---------|-o-------|--o------|---------|--o------|--o------|--o--> time - T0 T1 T2.2 T3.2 T5.3 T6.3 + *---------o-*-------|-o*------|-O-------|-o*------|--*------|--*--> time + T0 T1.2 T2.2 T3.2 T4.2 T5.3 T6.3 + + -o- "Expected ticks" + -*- "Delivered ticks" + -O- "Undelivered ticks (skipped)" ``` +
""" def __init__(self, *, delay_tolerance: timedelta = timedelta(0)):