Conversation
|
Updated: pushed 3013200 and rewrote the description. The PR originally only added the styling and deliberately left existing notices alone, which meant it landed a styling rule that almost nothing in this repo used. It now also brings every deprecation in line with the deprecations guide, which turned out to be most of them:
That takes the rendered count from 0 to 43. Two things I would like a second opinion on:
Two tests asserted a full message and were updated; the rest match a substring.
|
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Decorated properties currently render duplicate notices, and several messages and tests do not follow the newly documented exact format.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 4
Open (5)
What changed in this PR
Adds consistent deprecation notices to generated API documentation.
Changes:
- Adds and styles generated
Deprecatedadmonitions. - Standardizes deprecation messages and documentation.
- Updates warning-message tests.
| File | Description |
|---|---|
pyproject.toml |
Adds the Griffe deprecation extension. |
mkdocs.yml |
Configures generated deprecation admonitions. |
docs/_css/mkdocstrings.css |
Styles deprecated notices. |
docs/wrapping-guide/deprecation-and-compatibility.md |
Documents the new convention. |
src/frequenz/client/common/streaming/_event.py |
Documents enum-member deprecation. |
src/frequenz/client/common/proto/_datetime.py |
Updates converter deprecation. |
src/frequenz/client/common/pagination/proto/v1alpha8/_pagination_info.py |
Updates converter deprecation. |
src/frequenz/client/common/microgrid/electrical_components/proto/v1alpha8/_category.py |
Updates legacy converter notices. |
src/frequenz/client/common/microgrid/electrical_components/_state_code.py |
Documents enum-member deprecation. |
src/frequenz/client/common/microgrid/electrical_components/_diagnostic_code.py |
Documents enum-member deprecation. |
src/frequenz/client/common/microgrid/electrical_components/_category.py |
Documents category and member deprecations. |
src/frequenz/client/common/microgrid/components/__init__.py |
Updates ComponentId deprecation. |
src/frequenz/client/common/metrics/proto/v1alpha8/_sample.py |
Updates legacy converter notices. |
src/frequenz/client/common/metrics/proto/v1alpha8/_bounds.py |
Updates bounds converter notices. |
src/frequenz/client/common/metrics/_sample.py |
Updates property and enum deprecations. |
src/frequenz/client/common/metrics/_metric.py |
Documents enum-member deprecation. |
src/frequenz/client/common/grid/proto/v1alpha8/_delivery_area.py |
Updates converter deprecation. |
src/frequenz/client/common/grid/_delivery_area.py |
Documents delivery-area deprecations. |
tests/proto/test_datetime.py |
Updates exact warning assertion. |
tests/pagination/proto/v1alpha8/test_pagination_info.py |
Updates exact warning assertion. |
tests/metrics/test_sample_metric_sample.py |
Updates property warning assertion. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
daniel-zullo-frequenz
left a comment
There was a problem hiding this comment.
LGTM, there are a few comments from Copilot but I think most of them can be ignored. I'll approve it again once you've assessed/resolved the existing comments
9e5cd51 to
441e8ef
Compare
|
Updated, but I'm exploring an mkdocs extension so some of the fixes here are not necessary (like the duplicated |
Style the `deprecated` admonition class like a warning, but with the `material/grave-stone` icon and its own colour, so deprecation notices read as deprecation notices and not as generic warnings. That class is what a hand-written `Deprecated:` admonition in a docstring produces, and also what the griffe extension added next will emit, so a single rule covers both sources. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Wire two griffe extensions into the mkdocstrings handler options, so deprecated symbols get a "Deprecated" admonition and a `deprecated` label in the API reference with no docstring edit at all: * `griffe-warnings-deprecated` handles every class and function decorated with `typing_extensions.deprecated`. * `griffe-frequenz-core` handles what `frequenz-core` deprecates through a call instead of a decorator: enum members wrapped in `frequenz.core.enum.deprecated_member()`, and module aliases built with `frequenz.core.warnings.deprecated_aliases()`. It doesn't import `frequenz-core`, so it only goes in the docs dependencies. Both extensions have `kind` set to `deprecated` rather than their default, so they emit `class="deprecated"`, which is exactly what a hand-written `Deprecated:` admonition produces. The CSS rule added in the previous commit then styles all three, and they are visually indistinguishable. That matters because some cases still need the admonition written by hand: a single function argument, a whole module, a property (griffe-warnings-deprecated doesn't look at the decorators of a property), and a message the extensions can't read statically, such as one built by calling a function. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Rewrite every `@deprecated` message in the form the guide asks for: the fully qualified name of the deprecated symbol, the version it was deprecated in, and the replacement as a bare `[name][]` cross-reference, so the admonition generated from it links to the replacement. The old `Warning: Deprecated` admonitions go away, since the generated ones replace them; whatever they said beyond "use X instead" stays as prose in the docstring body. The `deprecated_member()` messages of the `UNSPECIFIED` members follow the same form, and get their admonition generated too. Where no extension can produce one, a `Deprecated:` admonition is written by hand instead: * The members of `ElectricalComponentCategory`, whose message is built by a helper function, which the extension can't read statically. * `MetricSample.sample_time` and `MetricSample.bounds`, because griffe-warnings-deprecated doesn't look at the decorators of a property. * The `bounds` argument of `MetricSample` and a `None` `code` in `DeliveryArea`, which deprecate an argument and not a symbol. * Constructing an invalid `DeliveryArea`, which is being made stricter. `MetricSample.sample_time` now points at `get_sample_time()`, not at `sample_time2`: the property returns a `datetime` and raises `InvalidDatetimeError` for a malformed timestamp, which is exactly what `get_sample_time()` does, while `sample_time2` has a different type and is itself going away when it is renamed back to `sample_time`. The release notes now say the same. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
441e8ef to
f7e2a35
Compare
The previous commits changed every deprecation notice in the repo but left the wrapping guide describing the old message form, `"<old FQCN> is deprecated. Use <new FQCN> instead."`, with no version and no cross-reference brackets. The guide is what a contributor reads before writing a new deprecation, so leaving it behind would reintroduce the old form. It now describes the form the code uses and why: the version in the sentence because a separate "since" line cannot be expressed through the decorator, the replacement as a bare `[name][]` cross-reference so the generated admonition links to it, no backticks because the same string is printed as a runtime warning, and implicit concatenation of single-line strings because a triple-quoted message carries its indentation into both the cross-reference and the terminal. The worked example is updated to match, and now escapes the brackets and dots in its `pytest.deprecated_call()` regex. That is easy to get wrong silently, because `match` is a search and an unescaped `[...]` is a character class that still matches something. It also explains where the admonition comes from, and so why the message has to be made of string literals: the documentation build reads it without running the code, and renders nothing for a message it can't read. The cases that still need a hand-written `Deprecated:` admonition are listed, since the guide never mentioned them: an argument, construction being made stricter, a property, and a message that isn't a literal. The `deprecated_member` paragraph now says its message gets the same treatment, with an example. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
9409d1d to
2538fe8
Compare
The next commits use `frequenz.core.warnings`, which is not released yet: the module itself is added by frequenz-floss/frequenz-core-python#199, and the per-alias `DeprecatedAlias` messages used here come from frequenz-floss#200, stacked on frequenz-floss#199. Until both are merged and released, depend on frequenz-floss#200's head directly. The dependency goes through the upstream repository URL rather than the fork the PR comes from, because the fork has no tags: built from there, the package gets version `0.0.postN`, while from upstream it is `1.4.0.post34`, which keeps any other `frequenz-core >= 1.4` requirement in the dependency tree satisfiable. This commit must be replaced with `frequenz-core >= 1.5.0, < 2` once v1.5.0 is released, before merging. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
The library silences the deprecation warnings it raises itself, for example when a converter touches a deprecated `UNSPECIFIED` member, with a `warnings.catch_warnings()` block plus an "ignore" filter. Entering and leaving such a block invalidates the deduplication history of every module (python/cpython#73858), so every warning that was already shown, from this library or from anywhere else, is shown again after each call. Downstream this turned into tens of thousands of repeated warnings in a single test run. Replace all 16 blocks with `frequenz.core.warnings.ignoring_deprecations()`, which adds the filter without touching the history. The blocks keep their current extent, so exactly the same warnings are silenced as before; narrowing some of them is a separate change. The `EnumParityTest` scaffold gets the same treatment: it ships in the package and runs inside downstream test suites. Two regression tests call a deprecated converter and a `str()` that silences a deprecation in a loop, under the "default" action, and check that each warning is shown only once. Both fail with the old blocks. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
The tests used `warnings.catch_warnings()` blocks for two different things, now done by the `frequenz.core.warnings` helper made for each: * An "ignore" filter, to call deprecated APIs the test needs as setup, becomes `ignoring_deprecations()`, like in the library. * An "error" filter, to check that a replacement API doesn't go through a deprecated one, becomes `asserting_no_deprecations()`. It records the warnings instead of raising them inside the code under test, so a broad `except` there can't swallow the failure, and it reports every offending warning with its location when the block ends. The blocks that record warnings to check what a helper lets through are left alone: that is what `catch_warnings(record=True)` is for. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
The previous commits moved the library and its tests to the `frequenz.core.warnings` helpers, but the guide still told contributors to silence inner deprecations with `warnings.catch_warnings()`, which is the exact bug they fix. Anyone following it would bring the warning amplification back. The deprecation guide gets two new sections and an updated one: * Keeping a moved symbol importable with `deprecated_aliases()`, including the `TYPE_CHECKING`/`else` structure it needs, a message carrying the version, and when a deprecated class is the better fit, as with `ComponentId`. * Silencing only the deprecations the library raises itself, with `ignoring_deprecations()` around the one statement, and why `catch_warnings()` must not be used for it. * Testing that a replacement doesn't warn with `asserting_no_deprecations()` instead of an "error" filter. The testing guide points at both helpers. The helpers are mentioned as plain code rather than cross-references because the frequenz-core inventory will only have them once v1.5.0 is released. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
2538fe8 to
46d6b2a
Compare



Gets the deprecation tooling in this repo up to date before the 0.4.1 release: deprecation notices that actually reach the API reference, and warnings that stop repeating downstream.
Warning
This depends on frequenz-floss/frequenz-core-python#200 (stacked on #199), which isn't released yet. The
WIP:commit pinsfrequenz-coreto that PR's head, and has to be replaced withfrequenz-core >= 1.5.0, < 2before merging.The docs side styles the
Deprecatedadmonition and generates it automatically: griffe-warnings-deprecated covers symbols decorated with@deprecated, and griffe-frequenz-core covers enum members wrapped indeprecated_member()and module aliases built withdeprecated_aliases(). Every deprecation message in the repo then follows the deprecations guide, and hand-written admonitions stay only where nothing can generate one. The commit message lists those cases.The code side replaces the 16
warnings.catch_warnings()blocks the library used to silence its own deprecations withfrequenz.core.warnings.ignoring_deprecations(). Entering and leaving acatch_warnings()block resets the deduplication history of the whole program (python/cpython#73858), so every warning already shown, from any code, was shown again on each converter call: calling two deprecated converters 1,000 times showed 3,000 warnings instead of 3. Two regression tests cover it. The tests useignoring_deprecations()andasserting_no_deprecations()too, and the wrapping guide now explains both helpers anddeprecated_aliases().Worth a reviewer's eye:
MetricSample.sample_timerecommendsget_sample_time()rather thansample_time2, because that's its exact replacement (same type, same error for a malformed timestamp). The failing test on the previous push expectedsample_time2; the test was the wrong side.ElectricalComponentCategorymembers keep their hand-written admonitions and get nodeprecatedlabel, because their message comes from a helper function the extension can't read. Writing 20 long literal messages out seemed worse.DeliveryAreaconstruction deprecations are unchanged. The guide's message form is for the decorator, and downstream tests may match those texts.Each alias in the
deprecated_aliases()example in the wrapping guide now gives its ownsince, the version it is deprecated in, using theDeprecatedAliasform frequenz-floss/frequenz-core-python#200 added on top of #199, so aliases deprecated in different releases can each say theirs.messageis still there as the escape hatch for a custom wording.