-
Notifications
You must be signed in to change notification settings - Fork 221
refactor: separate metric definition from metric value and share comp… #154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
AumPatel1
wants to merge
3
commits into
plexe-ai:main
Choose a base branch
from
AumPatel1:refactor-metric-separation
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -22,6 +22,8 @@ | |||||||||||||
|
|
||||||||||||||
| from enum import Enum | ||||||||||||||
| from functools import total_ordering | ||||||||||||||
| from typing import Optional | ||||||||||||||
| from weakref import WeakValueDictionary | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| class ComparisonMethod(Enum): | ||||||||||||||
|
|
@@ -98,31 +100,138 @@ def compare(self, value1: float, value2: float) -> int: | |||||||||||||
| raise ValueError("Invalid comparison method.") | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| # todo: this class is a mess as it mixes concerns of a metric and a metric value; needs refactoring | ||||||||||||||
| # Internal cache for sharing MetricComparator instances across all metrics | ||||||||||||||
| # This ensures only one comparator object exists per unique (method, target, epsilon) combination | ||||||||||||||
| _comparator_cache: WeakValueDictionary = WeakValueDictionary() | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def _get_shared_comparator(comparison_method: ComparisonMethod, target: Optional[float] = None, epsilon: float = 1e-9) -> MetricComparator: | ||||||||||||||
| """ | ||||||||||||||
| Get or create a shared MetricComparator instance. | ||||||||||||||
|
|
||||||||||||||
| This function ensures that identical comparators are reused across all Metric instances, | ||||||||||||||
| reducing memory usage and ensuring consistency. | ||||||||||||||
|
|
||||||||||||||
| :param comparison_method: The comparison method. | ||||||||||||||
| :param target: Optional target value for TARGET_IS_BETTER. | ||||||||||||||
| :param epsilon: Tolerance for floating-point comparisons. | ||||||||||||||
| :return: A shared MetricComparator instance. | ||||||||||||||
| """ | ||||||||||||||
| # Create a cache key from the comparator parameters | ||||||||||||||
| cache_key = (comparison_method, target, epsilon) | ||||||||||||||
|
|
||||||||||||||
| # Try to get existing comparator from cache | ||||||||||||||
| if cache_key in _comparator_cache: | ||||||||||||||
| return _comparator_cache[cache_key] | ||||||||||||||
|
|
||||||||||||||
| # Create new comparator and cache it | ||||||||||||||
| comparator = MetricComparator(comparison_method, target, epsilon) | ||||||||||||||
| _comparator_cache[cache_key] = comparator | ||||||||||||||
| return comparator | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| class _MetricDefinition: | ||||||||||||||
| """ | ||||||||||||||
| Internal class representing a metric type definition. | ||||||||||||||
|
|
||||||||||||||
| This separates the metric definition (what it is) from the metric value (a measurement). | ||||||||||||||
| Metric definitions are immutable and can be shared across multiple metric values. | ||||||||||||||
|
|
||||||||||||||
| This is an internal implementation detail - users should not interact with this class directly. | ||||||||||||||
| """ | ||||||||||||||
|
|
||||||||||||||
| def __init__(self, name: str, comparator: MetricComparator): | ||||||||||||||
| """ | ||||||||||||||
| Initialize a metric definition. | ||||||||||||||
|
|
||||||||||||||
| :param name: The name of the metric. | ||||||||||||||
| :param comparator: The shared comparator instance. | ||||||||||||||
| """ | ||||||||||||||
| self._name = name | ||||||||||||||
| self._comparator = comparator | ||||||||||||||
|
|
||||||||||||||
| @property | ||||||||||||||
| def name(self) -> str: | ||||||||||||||
| """The name of the metric.""" | ||||||||||||||
| return self._name | ||||||||||||||
|
|
||||||||||||||
| @property | ||||||||||||||
| def comparator(self) -> MetricComparator: | ||||||||||||||
| """The shared comparator instance.""" | ||||||||||||||
| return self._comparator | ||||||||||||||
|
|
||||||||||||||
| def __eq__(self, other) -> bool: | ||||||||||||||
| """Check if two metric definitions are equal.""" | ||||||||||||||
| if not isinstance(other, _MetricDefinition): | ||||||||||||||
| return False | ||||||||||||||
| return ( | ||||||||||||||
| self.name == other.name | ||||||||||||||
| and self.comparator.comparison_method == other.comparator.comparison_method | ||||||||||||||
| and self.comparator.target == other.comparator.target | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| def __hash__(self) -> int: | ||||||||||||||
| """Hash the metric definition.""" | ||||||||||||||
| return hash((self.name, self.comparator.comparison_method, self.comparator.target)) | ||||||||||||||
|
||||||||||||||
| def __hash__(self) -> int: | |
| """Hash the metric definition.""" | |
| return hash((self.name, self.comparator.comparison_method, self.comparator.target)) | |
| def __hash__(self) -> int: | |
| """Hash the metric definition.""" | |
| return hash((self.name, self.comparator.comparison_method, self.comparator.target, self.comparator.epsilon)) |
Prompt To Fix With AI
This is a comment left during a code review.
Path: plexe/internal/models/entities/metric.py
Line: 173:175
Comment:
**logic:** `epsilon` is missing from hash calculation - must include all fields used in `__eq__` to maintain hash contract
```suggestion
def __hash__(self) -> int:
"""Hash the metric definition."""
return hash((self.name, self.comparator.comparison_method, self.comparator.target, self.comparator.epsilon))
```
How can I resolve this? If you propose a fix, please make it concise.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic:
epsilonis missing from equality check - two metric definitions with different epsilon values will be considered equal, causing incorrect behavior when comparing metrics with different epsilon tolerancesPrompt To Fix With AI