Skip to content

Commit f7686b6

Browse files
Merge pull request #634 from Blueprints-org/630-feature-request-add-comparisonformula-1
630 feature request add comparisonformula
2 parents 03c24d7 + e712475 commit f7686b6

File tree

2 files changed

+175
-4
lines changed

2 files changed

+175
-4
lines changed

blueprints/codes/formula.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,73 @@ def _evaluate(*args, **kwargs) -> float | bool:
8585
The result of the formula.
8686
This is an abstract method and must be implemented in all subclasses.
8787
"""
88+
89+
90+
class ComparisonFormula(Formula):
91+
"""Base class for comparison formulas used in the codes."""
92+
93+
def __new__(cls, *args, **kwargs) -> "ComparisonFormula":
94+
"""Method for creating a new instance of the class."""
95+
lhs = cls._evaluate_lhs(*args, **kwargs)
96+
rhs = cls._evaluate_rhs(*args, **kwargs)
97+
result = cls._evaluate(*args, **kwargs)
98+
instance = float.__new__(cls, result)
99+
instance._lhs = lhs # noqa: SLF001
100+
instance._rhs = rhs # noqa: SLF001
101+
instance._initialized = False # noqa: SLF001
102+
return instance
103+
104+
@staticmethod
105+
@abstractmethod
106+
def _evaluate_lhs(*args, **kwargs) -> float:
107+
"""Abstract method for the logic of the left-hand side of the comparison formula.
108+
109+
Returns
110+
-------
111+
float
112+
The left-hand side value of the comparison.
113+
"""
114+
115+
@staticmethod
116+
@abstractmethod
117+
def _evaluate_rhs(*args, **kwargs) -> float:
118+
"""Abstract method for the logic of the right-hand side of the comparison formula.
119+
120+
Returns
121+
-------
122+
float
123+
The right-hand side value of the comparison.
124+
"""
125+
126+
@property
127+
def lhs(self) -> float:
128+
"""Property for getting the left-hand side of the comparison.
129+
130+
Returns
131+
-------
132+
float
133+
The left-hand side value of the comparison.
134+
"""
135+
return self._lhs # type: ignore[attr-defined]
136+
137+
@property
138+
def rhs(self) -> float:
139+
"""Property for getting the right-hand side of the comparison.
140+
141+
Returns
142+
-------
143+
float
144+
The right-hand side value of the comparison.
145+
"""
146+
return self._rhs # type: ignore[attr-defined]
147+
148+
@property
149+
@abstractmethod
150+
def unity_check(self) -> float:
151+
"""Property to present the unity check of the formula.
152+
153+
Returns
154+
-------
155+
float
156+
The unity check.
157+
"""

tests/codes/test_formula.py

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
"""Module for testing the Formula class."""
1+
"""Module for testing the Formula classes."""
22

33
import pytest
44

5-
from blueprints.codes.formula import Formula
5+
from blueprints.codes.formula import ComparisonFormula, Formula
66

77

88
class FormulaTest(Formula):
@@ -32,7 +32,6 @@ def _evaluate(
3232

3333
def test_raise_error_when_changing_value_after_initialization() -> None:
3434
"""Test that an error is raised when changing a value after initialization."""
35-
# example values
3635
first = 1
3736
second = 2
3837
dummy_testing_formula = FormulaTest(first=first, second=second)
@@ -42,9 +41,111 @@ def test_raise_error_when_changing_value_after_initialization() -> None:
4241

4342
def test_raise_not_implemented_error_detailed_result() -> None:
4443
"""Test that an error is raised when the detailed result is not implemented."""
45-
# example values
4644
first = 1
4745
second = 2
4846
dummy_testing_formula = FormulaTest(first=first, second=second)
4947
with pytest.raises(NotImplementedError):
5048
_ = dummy_testing_formula.detailed_result
49+
50+
51+
class ComparisonFormulaTest(ComparisonFormula):
52+
"""Dummy comparison formula for testing purposes."""
53+
54+
label = "Dummy testing comparison formula"
55+
source_document = "Dummy testing document"
56+
57+
def __init__(
58+
self,
59+
a: float,
60+
b: float,
61+
c: float,
62+
) -> None:
63+
"""Dummy comparison formula for testing purposes."""
64+
super().__init__()
65+
self.a = a
66+
self.b = b
67+
self.c = c
68+
69+
@staticmethod
70+
def _evaluate(
71+
a: float,
72+
b: float,
73+
c: float,
74+
) -> float:
75+
"""Dummy formula for testing purposes."""
76+
return ComparisonFormulaTest._evaluate_lhs(a=a, b=b) <= ComparisonFormulaTest._evaluate_rhs(c=c)
77+
78+
@staticmethod
79+
def _evaluate_lhs(a: float, b: float, **_) -> float:
80+
"""Left-hand side value of the comparison."""
81+
return a + b
82+
83+
@staticmethod
84+
def _evaluate_rhs(c: float, **_) -> float:
85+
"""Right-hand side value of the comparison."""
86+
return c / 2
87+
88+
@property
89+
def unity_check(self) -> float:
90+
"""Property to present the unity check of the formula."""
91+
return self.lhs / self.rhs
92+
93+
94+
def test_comparison_formula_evaluation() -> None:
95+
"""Test that the formula returns the correct result."""
96+
a = 10
97+
b = 5
98+
c = 40
99+
100+
# check passing condition (lhs <= rhs) = True
101+
formula = ComparisonFormulaTest(a=a, b=b, c=c)
102+
assert formula
103+
104+
# check failing condition (lhs > rhs) = False
105+
a = 30
106+
formula = ComparisonFormulaTest(a=a, b=b, c=c)
107+
assert not formula
108+
109+
110+
def test_comparison_formula_lhs_property() -> None:
111+
"""Test that the lhs property returns the correct result."""
112+
a = 10
113+
b = 5
114+
c = 40
115+
formula = ComparisonFormulaTest(a=a, b=b, c=c)
116+
117+
# The lhs should be a + b = 10 + 5 = 15
118+
assert formula.lhs == 15
119+
120+
121+
def test_comparison_formula_rhs_property() -> None:
122+
"""Test that the rhs property returns the correct result."""
123+
a = 10
124+
b = 5
125+
c = 40
126+
formula = ComparisonFormulaTest(a=a, b=b, c=c)
127+
128+
# The rhs should be c / 2 = 40 / 2 = 20
129+
assert formula.rhs == 20
130+
131+
132+
def test_comparison_formula_unity_check_property() -> None:
133+
"""Test that the unity check property returns the correct result."""
134+
a = 10
135+
b = 5
136+
c = 40
137+
formula = ComparisonFormulaTest(a=a, b=b, c=c)
138+
139+
# The unity check should be lhs / rhs = 15 / 20 = 0.75
140+
assert formula.unity_check == 0.75
141+
142+
143+
def test_comparison_formula_change_value_after_initialization() -> None:
144+
"""Test that an error is raised when changing a value after initialization."""
145+
a = 10
146+
b = 5
147+
c = 40
148+
formula = ComparisonFormulaTest(a=a, b=b, c=c)
149+
150+
with pytest.raises(AttributeError):
151+
formula.a = 30

0 commit comments

Comments
 (0)