Griffe Extensions for frequenz-core
Introduction
A collection of Griffe extensions
that teach mkdocstrings about
frequenz-core
helpers.
Some of those helpers express information that Griffe cannot recover from static analysis alone, so the API documentation generated for code using them comes out incomplete. Each extension here fills one of those gaps, and new ones are added as more helpers need the same treatment.
The first gap covered is deprecation. frequenz-core marks some APIs as
deprecated through a function call instead of a decorator, which neither the
@deprecated decorator support in Griffe nor
griffe-warnings-deprecated
can detect.
The extensions match fully qualified names as strings and never import
frequenz-core, so this package does not depend on it and can document any
project that uses those helpers.
Installation
Add griffe-frequenz-core to the dependencies your documentation is built
with, next to mkdocstrings. Then enable each extension you want by its module
path, in the extensions option of the mkdocstrings Python handler.
Documenting deprecations
The griffe_frequenz_core.deprecations extension documents the deprecations
frequenz-core expresses through a call. It is meant to run next to
griffe-warnings-deprecated, which documents the ones expressed through a
decorator:
plugins:
- mkdocstrings:
handlers:
python:
options:
extensions:
- griffe_warnings_deprecated
- griffe_frequenz_core.deprecations
Its defaults match griffe-warnings-deprecated, so with this configuration
both kinds of deprecation are rendered the same way. Every deprecation the
extension recognizes gets the same three things a decorated one gets:
- a
deprecatedlabel, - the message stored in the object's
deprecatedfield, - an admonition with the message, inserted at the top of its docstring.
If you have a custom admonition style for deprecations, you can set the kind
option to match it.
plugins:
- mkdocstrings:
handlers:
python:
options:
extensions:
- griffe_warnings_deprecated:
kind: deprecated
- griffe_frequenz_core.deprecations:
kind: deprecated
Recognized frequenz-core helpers
frequenz-core helper |
Written as | Documented object |
|---|---|---|
frequenz.core.warnings.deprecated_aliases() |
the value of a module __getattr__ |
every alias in the table |
frequenz.core.enum.deprecated_member() |
the value of an enum member | the enum member |
frequenz.core.enum.DeprecatedMember |
the value of an enum member | the enum member |
Calls are matched by the fully qualified path Griffe resolves from the
module's imports, so an import under another name, such as
from frequenz.core.enum import deprecated_member as dm, is recognized too.
Deprecated module aliases
deprecated_aliases() keeps a moved symbol importable from its old module
through a module __getattr__, with the names declared again under
TYPE_CHECKING for type checkers:
from typing import TYPE_CHECKING, TypeAlias
from frequenz.core.warnings import deprecated_aliases
if TYPE_CHECKING:
from mypkg.newmod import Gadget as _Gadget
from mypkg.newmod import Widget as _Widget
Widget: TypeAlias = _Widget
"""A widget that does widget things."""
Doohickey: TypeAlias = _Gadget
"""A gadget, formerly known as `Doohickey`."""
else:
__getattr__ = deprecated_aliases(
__name__,
{
"Widget": "mypkg.newmod",
"Doohickey": "mypkg.newmod:Gadget",
},
)
If this is mypkg.oldmod, the documentation of Widget starts with an
admonition saying "mypkg.oldmod.Widget is deprecated. Use
mypkg.newmod.Widget instead.", and its value is rendered as
mypkg.newmod.Widget instead of the private _Widget. A target written as
"module:name" renames the symbol as well as moving it, so Doohickey points
at mypkg.newmod.Gadget.
The details of what gets documented:
- Every name in the table is marked, whether or not it is declared under
TYPE_CHECKING. A name with no declaration gets a new module attribute, so it still appears in the documentation. - The message is the
messageargument of the call when there is one, and thedefault_messageoption otherwise.{old}is replaced with the path of the alias, formatted as code, and{new}with a link to the target. When the target is neither in your documentation nor in a configured inventory, the link is rendered as plain code instead of failing a strict build. - The table may be passed positionally or as
aliases=. The other arguments, such ascategoryandstacklevel, don't change the documentation. - The call has to be assigned directly to the module's
__getattr__. Adef __getattr__()that callsdeprecated_aliases()inside is not recognized, and neither is a__getattr__built by anything else.
Deprecated enum members
deprecated_member(), or the DeprecatedMember class it returns, wraps the
value of an enum member to deprecate it:
from frequenz.core.enum import DeprecatedMember, Enum, deprecated_member
class TaskStatus(Enum):
OPEN = 1
PENDING = deprecated_member(1, "PENDING is deprecated, use OPEN instead")
WAITING = DeprecatedMember(1, "WAITING is deprecated, use OPEN instead")
Both members are marked with their message as written, and their value is
rendered as the real value instead of the wrapper call, so the documentation
shows PENDING = 1.
Hand-written admonitions
When the docstring of a deprecated object already has a deprecation
admonition, the extension leaves the docstring alone and only adds the label
and the deprecated field. It counts as a deprecation admonition if it is a
Deprecated: section, or an admonition whose title matches the title
option, ignoring case. Write one when the message is not enough, for example
to say since which version the symbol is deprecated:
if TYPE_CHECKING:
Widget: TypeAlias = _Widget
"""A widget that does widget things.
Deprecated:
`mypkg.oldmod.Widget` is deprecated since v1.2.0. Use
[`mypkg.newmod.Widget`][] instead.
"""
Known limitations
Griffe reads the source without running it, so a deprecation is only documented when the call can be understood from the syntax tree alone:
- Messages, alias names and alias targets must be string literals written in
the call. A message held in a constant, built by an f-string or joined from
pieces cannot be recovered. An enum member with such a message is left
unmarked, an alias table entry with such a name or target is skipped, and an
alias table with such a
messagefalls back to thedefault_messageoption, so its documentation no longer matches the runtime warning. - The alias table must be a dict literal written in the call, passed as the
second positional argument or as
aliases=. A table held in a constant, as indeprecated_aliases(__name__, ALIASES), cannot be read, and every alias in it is left unmarked. - The arguments of
deprecated_member()andDeprecatedMembermust be written out, positionally or by keyword.deprecated_member(*ARGS)is not recognized, and the member is left unmarked.
Each case the extension skips is logged at debug level, which
mkdocs build --verbose shows.
Options
| Option | Default | Effect |
|---|---|---|
kind |
danger |
The kind of the admonition, which is also its CSS class. |
title |
Deprecated |
The title of the admonition. An empty title or null renders none. |
label |
deprecated |
The label added to deprecated objects. null adds none. |
alias_table_functions |
frequenz.core.warnings.deprecated_aliases |
The paths of the functions that build a module __getattr__. |
member_wrapper_functions |
frequenz.core.enum.deprecated_member, frequenz.core.enum.DeprecatedMember |
The paths of the callables that wrap a deprecated enum member's value. |
default_message |
{old} is deprecated. Use {new} instead. |
The alias message used when the call passes no message. |
show_target |
true |
Render an alias' value as its target, not the private name. |
The two path options are lists, and setting one replaces its default. To match
a helper of your own as well as the frequenz-core one, list both:
extensions:
- griffe_frequenz_core.deprecations:
alias_table_functions:
- frequenz.core.warnings.deprecated_aliases
- mypkg.compat.moved_to
A helper of your own is read with the signature of the one it stands in for.
For an alias table that is deprecated_aliases(): the table is its second
positional argument or aliases=, and the message is message=. For an enum
member wrapper it is deprecated_member(value, message), each passed
positionally or by keyword.
They are options so that, if frequenz-core renames or moves a helper, you can
point them at the new path without waiting for a release of this package. For
the same reason, default_message has to follow the default of
deprecated_aliases(), since that is what the runtime warning says.
There is one deliberate difference from griffe-warnings-deprecated: given an
empty title, it puts the message in the admonition title, and this
extension does not. The message contains a link to the target, which does not
belong in a title, and the title is also what tells a hand-written admonition
apart.
Supported Platforms
The following platforms are officially supported (tested):
- Python: 3.11
- Operating System: Ubuntu Linux 20.04
- Architectures: amd64, arm64
Contributing
If you want to know how to build this project and contribute to it, please check out the Contributing Guide.
Metadata
Release files for griffe-frequenz-core 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| griffe_frequenz_core-1.0.0.tar.gz | 19.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| griffe_frequenz_core-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.6 kB
Release files / griffe_frequenz_core-1.0.0.tar.gz
| Download URL | griffe_frequenz_core-1.0.0.tar.gz |
|---|---|
| Size | 19.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
19ab1fb54c1ab6fc2263b63785350c32c274a5ec8615829781b095b1d63e77fa
|
|
BLAKE2b-256 checksum How to use checksums |
9b8b9ecb803d94f296c501d991e1d2e0fd37350255657e6141f5380f6675cced
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / griffe_frequenz_core-1.0.0-py3-none-any.whl
| Download URL | griffe_frequenz_core-1.0.0-py3-none-any.whl |
|---|---|
| Size | 13.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a8528037560be8246e2d310dbd441f136ac6fffe632eef4eb52f5b23b92361ae
|
|
BLAKE2b-256 checksum How to use checksums |
6c2fd5f07617accf2744b5ec5b0915b9cde15fedc97eaf8f27034c325158c6a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency log