| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Draft because it is based on #255, but other than that it should be ready for review. |
Sorry, something went wrong.
There was a problem hiding this comment.
This PR updates frequenz-client-common’s public surface to be explicit about Python’s PEP 484 numeric-tower behavior by introducing a FloatInt = float | int alias and propagating it through affected dataclasses and accessors, preventing “looks exhaustive” runtime logic (e.g. match … case float():) from silently falling through on int values.
Changes:
Copilot reviewed 36 out of 36 changed files in this pull request and generated 3 comments.
Show a summary per file| File | Description |
|---|---|
| tests/types/_location/test_location.py | Extends location tests to accept/reject int lat/lon via FloatInt. |
| tests/types/_location/test_invalid_longitude.py | Verifies InvalidLongitude preserves int values and string formatting. |
| tests/types/_location/test_invalid_latitude.py | Verifies InvalidLatitude preserves int values and string formatting. |
| tests/test_float.py | Adds tests for the new FloatInt alias. |
| tests/microgrid/proto/v1alpha8/test_microgrid.py | Updates microgrid conversion tests (drops log assertions). |
| tests/microgrid/electrical_components/test_power_transformer.py | Updates transformer voltage typing/tests to FloatInt. |
| tests/microgrid/electrical_components/test_electrical_component_base.py | Adds tests for metric-config bounds accessor behavior. |
| tests/microgrid/electrical_components/proto/v1alpha8/test_electrical_component_base.py | Updates proto parsing tests for bounds/invalid-bounds preservation. |
| tests/metrics/test_sample_metric_sample.py | Updates MetricSample tests for bounds_set, invalid bounds sets, and FloatInt values. |
| tests/metrics/test_sample_aggregated_value.py | Updates aggregated metric value tests for FloatInt inputs. |
| tests/metrics/test_bounds.py | Removes old Bounds tests (replaced by new bounds test package). |
| tests/metrics/proto/v1alpha8/test_sample_metric_sample.py | Updates proto MetricSample tests for bounds_set + invalid bounds behavior. |
| tests/metrics/proto/v1alpha8/test_bounds.py | Adds coverage for bounds_from_proto2 and deprecations. |
| tests/metrics/_bounds/test_invalid_bounds.py | New unit tests for InvalidBounds. |
| tests/metrics/_bounds/test_invalid_bounds_set.py | New unit tests for InvalidBoundsSet. |
| tests/metrics/_bounds/test_invalid_bounds_set_error.py | New unit tests for InvalidBoundsSetError. |
| tests/metrics/_bounds/test_invalid_bounds_error.py | New unit tests for InvalidBoundsError. |
| tests/metrics/_bounds/test_bounds.py | New unit tests for Bounds (incl. FloatInt storage + membership). |
| tests/metrics/_bounds/test_bounds_set.py | New unit tests for BoundsSet normalization and membership. |
| tests/metrics/_bounds/test_base_bounds.py | New unit tests for non-instantiability of BaseBounds. |
| tests/metrics/_bounds/init.py | Introduces bounds test package. |
| src/frequenz/client/common/types/_location.py | Updates location types and accessors to use FloatInt. |
| src/frequenz/client/common/microgrid/proto/v1alpha8/_microgrid.py | Simplifies microgrid conversion and changes warning/log behavior. |
| src/frequenz/client/common/microgrid/electrical_components/proto/v1alpha8/_electrical_component.py | Updates parsing of metric bounds to preserve invalid bounds using bounds_from_proto2. |
| src/frequenz/client/common/microgrid/electrical_components/_power_transformer.py | Updates transformer voltages to FloatInt. |
| src/frequenz/client/common/microgrid/electrical_components/_electrical_component.py | Adds semantic accessor get_metric_config_bounds() and supports InvalidBounds. |
| src/frequenz/client/common/microgrid/electrical_components/init.py | Exports new typing helper(s) and updated symbols. |
| src/frequenz/client/common/metrics/proto/v1alpha8/_sample.py | Builds BoundsSet/InvalidBoundsSet from wire bounds using bounds_from_proto2. |
| src/frequenz/client/common/metrics/proto/v1alpha8/_bounds.py | Adds bounds_from_proto2 and deprecates older converters. |
| src/frequenz/client/common/metrics/proto/v1alpha8/init.py | Exports bounds_from_proto2. |
| src/frequenz/client/common/metrics/_sample.py | Migrates MetricSample to bounds_set, adds deprecations/backcompat, adds get_bounds_set(). |
| src/frequenz/client/common/metrics/_bounds.py | Introduces Base/Valid/Invalid bounds hierarchy plus BoundsSet and errors. |
| src/frequenz/client/common/metrics/init.py | Re-exports new bounds/bounds-set types and errors. |
| src/frequenz/client/common/_float.py | Adds FloatInt type alias and explanatory documentation. |
| src/frequenz/client/common/init.py | Exports FloatInt at package root. |
| RELEASE_NOTES.md | Adds upgrade notes and documents new APIs/deprecations. |
src/frequenz/client/common/metrics/_bounds.py:70
def __post_init__(self) -> None:
"""Validate these bounds."""
if self.lower is None:
return
if self.upper is None:
return
if self.lower > self.upper:
raise ValueError(
f"Lower bound ({self.lower}) must be less than or equal to upper "
f"bound ({self.upper})"
)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Sorry, something went wrong.
There was a problem hiding this comment.
Copilot reviewed 36 out of 36 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)src/frequenz/client/common/metrics/_bounds.py:66
def __post_init__(self) -> None:
"""Validate these bounds."""
if self.lower is None:
return
if self.upper is None:
return
if self.lower > self.upper:
Sorry, something went wrong.
PEP 484's numeric tower makes `int` assignable to any `float`-annotated parameter or field, even under `mypy --strict`, while at runtime `isinstance(1, float)` is `False`. Any field annotated `float` can therefore silently store an `int`, and code unwrapping it with `match … case float():` falls through to `assert_never()`, calls to `float`-only methods like `hex()` crash, and `type()`-based dispatch misbehaves — despite everything type-checking cleanly. There is no clean fix in current Python (see the discussion in frequenz-floss#250): runtime coercion at ingress was prototyped and measured ~2.3× slower on hot-path types, structural `Protocol` tricks don't close the widened variable and `Sequence` covariance holes, and narrowing match arms one by one leaves the annotation lying. So the decision is to stop lying instead: annotate every such value as `float | int`, which is what PEP 484 actually admits, at zero runtime cost. It is also forward-compatible with the typing-council proposal to make `float` mean `float | int` (python/typing-council#46). Add the `FloatInt` alias as the canonical spelling of that union. The alias gives the workaround a single documented home — explaining the trap, the `bool ⊂ int` leak. Follow-up commits migrate the existing `float` annotations to it. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
There was a problem hiding this comment.
python troubles.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
PEP 484's numeric tower makes int assignable to any float-annotated parameter or field, while at runtime isinstance(1, float) is False.
Any field annotated float can therefore silently store an int, and code unwrapping it with match … case float(): falls through to assert_never(), calls to float-only methods like hex() crash, and type()-based dispatch misbehaves — despite everything type-checking cleanly.
There is no clean fix in current Python (see the discussion in #250): runtime coercion at ingress was prototyped and measured ~2.3× slower on hot-path types, structural Protocol tricks don't close the widened variable and Sequence covariance holes, and narrowing match arms one by one leaves the annotation lying. So the decision is to stop lying instead: annotate every such value as float | int, which is what PEP 484 actually admits, at zero runtime cost. It is also forward-compatible with the typing-council proposal to make float mean float | int (python/typing-council#46).
This commit replaces all float annotations with FloatInt, a type alias for float | int.
Fixes #250.