What's needed?
The deprecations guide now separates the two texts every deprecation has:
- The warning, emitted at runtime and read in a terminal: plain text, starting with the fully qualified name of the deprecated symbol (the own deprecations
pytest filter relies on it), saying what to use instead, without the version.
- The notice, the
Deprecated: admonition in the API documentation: it says since which version the symbol is deprecated and links what to use instead.
griffe-frequenz-core generates the notice from the helpers' structured arguments wherever it can, and a hand-written Deprecated: admonition always replaces it. Two helpers don't fit this yet:
DeprecatedAlias(since=...) puts the version in the runtime warning, and since and message exclude each other, so an alias with a custom warning has no version for its notice.
deprecated_member() only takes the runtime message, so every deprecated enum member needs a hand-written notice, even for a plain rename.
Proposed solution
-
DeprecatedAlias's generated warning drops the version. It becomes {old} is deprecated. Use {new} instead. instead of {old} is deprecated since {since}. Use {new} instead. since stays, as documentation metadata only (read by griffe-frequenz-core). Update format_message() and the docstrings. Only the warning text changes, so this is not breaking.
-
DeprecatedAlias's since and message become independent. message only replaces the runtime warning, and since only feeds the notice, so both can be given, and so can neither. At least one of new_module and new_name is still required. Update _validate() and the __init__ overloads. This relaxes a check, so it is not breaking either. For example:
DeprecatedAlias(
"Sensor",
new_module="frequenz.client.common.microgrid.sensors",
since="v0.6.0",
message="{old} is deprecated. Use {new} instead, obtained from the client.",
)
This warns with the custom message, and its notice still says Deprecated since v0.6.0. Use [`frequenz.client.common.microgrid.sensors.Sensor`][] instead.
-
deprecated_member() and DeprecatedMember take a structured form too, like DeprecatedAlias:
class Metric(Enum):
AC_POWER_APPARENT = metrics_pb2.METRIC_AC_POWER_APPARENT
AC_APPARENT_POWER = deprecated_member(
metrics_pb2.METRIC_AC_POWER_APPARENT, new_name="AC_POWER_APPARENT", since="v0.18.0"
)
- New keyword-only
new_name (a member of the same enum) and since (documentation metadata only), and message gets a None default: deprecated_member(value, message=None, *, new_name=None, since=None). At least one of message and new_name is required, with __init__/function overloads so mypy checks it.
- Without
message, the warning is generated when the enum class is created, since only then are its module and qualified name known: {module}.{Enum}.{name} is deprecated. Use {module}.{Enum}.{new_name} instead.
- Class creation also checks that
new_name is a member of the same enum and isn't deprecated itself.
message stays a literal message, not an {old}/{new} template like DeprecatedAlias's, since existing messages may contain braces.
- Existing calls keep working:
value and message keep their position and names, and the new parameters are keyword-only. DeprecatedMember.message is public and typed str; to avoid changing its type, the generated message could be stored once the class is created instead (__deprecated_names__ keeps str values either way). That's to be decided in the PR.
-
Docstring examples follow the guide. deprecated_member()'s example ("PENDING is deprecated, use OPEN instead") uses the structured form, or a plain fully qualified runtime message plus a hand-written notice. DeprecatedAlias's docs say that since only feeds the documentation, that message only replaces the warning, and that the documentation is customized with a hand-written Deprecated: admonition on the name declared under TYPE_CHECKING.
All of this is additive, so it can go into v1.6.0.
Use cases
The client libraries built on frequenz-client-common deprecate dozens of enum members per release. Microgrid alone has about 35, almost all plain renames, each currently needing a runtime message plus a hand-written notice repeating the same information.
Additional context
What's needed?
The deprecations guide now separates the two texts every deprecation has:
pytestfilter relies on it), saying what to use instead, without the version.Deprecated:admonition in the API documentation: it says since which version the symbol is deprecated and links what to use instead.griffe-frequenz-coregenerates the notice from the helpers' structured arguments wherever it can, and a hand-writtenDeprecated:admonition always replaces it. Two helpers don't fit this yet:DeprecatedAlias(since=...)puts the version in the runtime warning, andsinceandmessageexclude each other, so an alias with a custom warning has no version for its notice.deprecated_member()only takes the runtime message, so every deprecated enum member needs a hand-written notice, even for a plain rename.Proposed solution
DeprecatedAlias's generated warning drops the version. It becomes{old} is deprecated. Use {new} instead.instead of{old} is deprecated since {since}. Use {new} instead.sincestays, as documentation metadata only (read bygriffe-frequenz-core). Updateformat_message()and the docstrings. Only the warning text changes, so this is not breaking.DeprecatedAlias'ssinceandmessagebecome independent.messageonly replaces the runtime warning, andsinceonly feeds the notice, so both can be given, and so can neither. At least one ofnew_moduleandnew_nameis still required. Update_validate()and the__init__overloads. This relaxes a check, so it is not breaking either. For example:This warns with the custom message, and its notice still says
Deprecated since v0.6.0. Use [`frequenz.client.common.microgrid.sensors.Sensor`][] instead.deprecated_member()andDeprecatedMembertake a structured form too, likeDeprecatedAlias:new_name(a member of the same enum) andsince(documentation metadata only), andmessagegets aNonedefault:deprecated_member(value, message=None, *, new_name=None, since=None). At least one ofmessageandnew_nameis required, with__init__/function overloads somypychecks it.message, the warning is generated when the enum class is created, since only then are its module and qualified name known:{module}.{Enum}.{name} is deprecated. Use {module}.{Enum}.{new_name} instead.new_nameis a member of the same enum and isn't deprecated itself.messagestays a literal message, not an{old}/{new}template likeDeprecatedAlias's, since existing messages may contain braces.valueandmessagekeep their position and names, and the new parameters are keyword-only.DeprecatedMember.messageis public and typedstr; to avoid changing its type, the generated message could be stored once the class is created instead (__deprecated_names__keepsstrvalues either way). That's to be decided in the PR.Docstring examples follow the guide.
deprecated_member()'s example ("PENDING is deprecated, use OPEN instead") uses the structured form, or a plain fully qualified runtime message plus a hand-written notice.DeprecatedAlias's docs say thatsinceonly feeds the documentation, thatmessageonly replaces the warning, and that the documentation is customized with a hand-writtenDeprecated:admonition on the name declared underTYPE_CHECKING.All of this is additive, so it can go into v1.6.0.
Use cases
The client libraries built on
frequenz-client-commondeprecate dozens of enum members per release. Microgrid alone has about 35, almost all plain renames, each currently needing a runtime message plus a hand-written notice repeating the same information.Additional context
griffe-frequenz-corewill read the new arguments once this is released: Read the structured deprecated_member() and DeprecatedAlias from frequenz-core 1.6 griffe-frequenz-core#10.@deprecateddecorator, which also only carries the warning: Document @deprecated symbols too, replacing griffe-warnings-deprecated griffe-frequenz-core#9.