Skip to content

Commit

Permalink
Import Self from fuzzylite to deal with python versions
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrada committed Sep 11, 2024
1 parent 6429702 commit 3e81b7f
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 63 deletions.
8 changes: 7 additions & 1 deletion fuzzylite/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@

from __future__ import annotations

__all__ = ["Array", "Scalar", "ScalarArray"]
__all__ = ["Array", "Scalar", "ScalarArray", "Self"]

import sys
from typing import Any, Union

import numpy as np
from numpy.typing import NDArray as Array

Scalar = Union[float, np.floating[Any], Array[np.floating[Any]]]
ScalarArray = Array[np.floating[Any]]

if sys.version_info >= (3, 11):
from typing import Self
else:
from typing_extensions import Self
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ select = [
"ISC", # flake8-implicit-str-concat
"N", # pep8 naming
"NPY", # NumPy-specific rules
"NPY201", # NumPy 2.0 specific rules
# "PD", # pandas-vet
"PLW", # warning
# "PTH", # flake8-use-pathlib
Expand Down
12 changes: 6 additions & 6 deletions tests/assert_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
from typing import Any, Generic, TypeVar

import numpy as np
from typing_extensions import Self

import fuzzylite as fl
from fuzzylite.types import Self

T = TypeVar("T")

Expand All @@ -37,11 +37,11 @@ def __init__(self, test: unittest.TestCase, actual: T) -> None:
self.test.maxDiff = None # show all differences

def repr_is(
self,
representation: str,
/,
with_alias: str | None = None,
validate: bool = True,
self,
representation: str,
/,
with_alias: str | None = None,
validate: bool = True,
) -> Self:
"""Asserts that the obtained object's representation is equal to the expected representation."""

Expand Down
24 changes: 11 additions & 13 deletions tests/test_defuzzifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@
from typing import Any

import numpy as np
from typing_extensions import Self

import fuzzylite as fl
from fuzzylite.types import Scalar
from fuzzylite.types import Scalar, Self
from tests.assert_component import BaseAssert


Expand All @@ -44,11 +43,11 @@ def has_attribute(self, **kwargs: Any) -> Self:
return self

def defuzzifies(
self,
minimum: float,
maximum: float,
terms: dict[fl.Term, float],
vectorized: bool = True,
self,
minimum: float,
maximum: float,
terms: dict[fl.Term, float],
vectorized: bool = True,
) -> Self:
"""Assert that the defuzzification of the given terms result in the expected values."""
for term, expected in terms.items():
Expand All @@ -61,7 +60,6 @@ def defuzzifies(
err_msg=f"{fl.Op.class_name(self.actual)}({term}) = {obtained}, but expected {expected}",
)
if vectorized:

class StackTerm(fl.Term):
def __init__(self, terms: list[fl.Term]) -> None:
super().__init__("_")
Expand Down Expand Up @@ -417,7 +415,7 @@ def test_weighted_defuzzifier(self) -> None:

class BaseWeightedDefuzzifier(fl.WeightedDefuzzifier):
def defuzzify(
self, term: fl.Term, minimum: float = fl.nan, maximum: float = fl.nan
self, term: fl.Term, minimum: float = fl.nan, maximum: float = fl.nan
) -> Scalar:
return fl.nan

Expand Down Expand Up @@ -528,8 +526,8 @@ def test_weighted_average(self) -> None:

defuzzifier = fl.WeightedAverage()
with self.assertRaisesRegex(
ValueError,
re.escape("expected an Aggregated term, but found <class 'fuzzylite.term.Triangle'>"),
ValueError,
re.escape("expected an Aggregated term, but found <class 'fuzzylite.term.Triangle'>"),
):
defuzzifier.defuzzify(fl.Triangle())

Expand Down Expand Up @@ -630,8 +628,8 @@ def test_weighted_sum(self) -> None:
defuzzifier = fl.WeightedSum()

with self.assertRaisesRegex(
ValueError,
re.escape("expected an Aggregated term, but found <class 'fuzzylite.term.Triangle'>"),
ValueError,
re.escape("expected an Aggregated term, but found <class 'fuzzylite.term.Triangle'>"),
):
defuzzifier.defuzzify(fl.Triangle())

Expand Down
10 changes: 5 additions & 5 deletions tests/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@

import black
import numpy as np
from typing_extensions import Self

import fuzzylite as fl
from fuzzylite.examples.mamdani.simple_dimmer import SimpleDimmer
from fuzzylite.types import Self
from tests.assert_component import BaseAssert


class EngineAssert(BaseAssert[fl.Engine]):
"""Engine assert."""

def has_type(
self,
expected: fl.Engine.Type | set[fl.Engine.Type],
/,
reasons: list[str] | None = None,
self,
expected: fl.Engine.Type | set[fl.Engine.Type],
/,
reasons: list[str] | None = None,
) -> Self:
"""Asserts the engine has the expected type."""
obtained_reasons: list[str] = []
Expand Down
10 changes: 5 additions & 5 deletions tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
)

import numpy as np
from typing_extensions import Self

import fuzzylite as fl
from fuzzylite.types import Self
from tests.assert_component import BaseAssert


Expand Down Expand Up @@ -79,9 +79,9 @@ class FunctionFactoryAssert(BaseAssert[fl.FunctionFactory]):
"""Function Factory assert."""

def contains_exactly(
self,
elements: set[str],
element_type: fl.Function.Element.Type | None = None,
self,
elements: set[str],
element_type: fl.Function.Element.Type | None = None,
) -> Self:
"""Assert the factory contains only the expected elements."""
if element_type == fl.Function.Element.Type.Operator:
Expand Down Expand Up @@ -129,7 +129,7 @@ def precedence_is_higher(self, a: str, b: str) -> Self:
elements[a].precedence,
elements[b].precedence,
msg=f"expected precedence of {a} ({elements[a].precedence}) > {b} ({elements[b].precedence}), "
f"but got {elements[a].precedence} <= {elements[b].precedence}",
f"but got {elements[a].precedence} <= {elements[b].precedence}",
)
return self

Expand Down
48 changes: 24 additions & 24 deletions tests/test_term.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
from typing import Callable, NoReturn

import numpy as np
from typing_extensions import Self

import fuzzylite as fl
import fuzzylite.library
from fuzzylite import Scalar, inf, nan
from fuzzylite.types import Self
from tests.assert_component import BaseAssert


Expand Down Expand Up @@ -77,7 +77,7 @@ def configured_as(self, parameters: str) -> Self:
return self

def has_memberships(
self, x_mf: dict[float, float], heights: Sequence[float] | None = None
self, x_mf: dict[float, float], heights: Sequence[float] | None = None
) -> Self:
"""Assert the term's membership function produces $f(x{_keys}) = mf_{values}$."""
inputs = fl.scalar(list(x_mf.keys()))
Expand Down Expand Up @@ -132,10 +132,10 @@ def has_tsukamotos(self, x_mf: dict[float, float]) -> Self:
return self

def apply(
self,
func: Callable[..., None],
args: Sequence[str] = (),
**keywords: dict[str, object],
self,
func: Callable[..., None],
args: Sequence[str] = (),
**keywords: dict[str, object],
) -> Self:
"""Applies function on the term with the arguments and keywords as parameters."""
func(self.actual, *args, **keywords)
Expand Down Expand Up @@ -800,19 +800,19 @@ def test_discrete(self) -> None:

term = fl.Discrete()
with self.assertRaisesRegex(
ValueError,
re.escape("expected xy to contain coordinate pairs, but it is empty"),
ValueError,
re.escape("expected xy to contain coordinate pairs, but it is empty"),
):
term.membership(0.0)
with self.assertRaisesRegex(
ValueError,
re.escape("expected xy to contain coordinate pairs, but it is empty"),
ValueError,
re.escape("expected xy to contain coordinate pairs, but it is empty"),
):
term.values = fl.Discrete.to_xy([], [])
term.membership(0.0)
with self.assertRaisesRegex(
ValueError,
re.escape("expected xy to have with 2 columns, but got 1 in shape (1,): [1.]"),
ValueError,
re.escape("expected xy to have with 2 columns, but got 1 in shape (1,): [1.]"),
):
term.values = fl.array([1.0])
term.membership(0.0)
Expand Down Expand Up @@ -1922,7 +1922,7 @@ def value_is(self, expected: str) -> FunctionNodeAssert:
return self

def evaluates_to(
self, expected: float, variables: dict[str, fl.Scalar] | None = None
self, expected: float, variables: dict[str, fl.Scalar] | None = None
) -> FunctionNodeAssert:
"""Assert the node evaluates to the expected value (optionally) given variables."""
obtained = self.actual.evaluate(variables)
Expand Down Expand Up @@ -1979,11 +1979,11 @@ def test_function(self) -> None:
output_a = fl.OutputVariable("o_A")
engine_a = fl.Engine("A", "Engine A", [input_a], [output_a])
with self.assertRaisesRegex(
ValueError,
re.escape(
"expected a map of variables containing the value for 'i_A', "
"but the map contains: {'x': 0.0}"
),
ValueError,
re.escape(
"expected a map of variables containing the value for 'i_A', "
"but the map contains: {'x': 0.0}"
),
):
fl.Function.create("engine_a", "2*i_A + o_A + x").membership(0.0)

Expand All @@ -2010,11 +2010,11 @@ def test_function(self) -> None:

function_a.variables = {"x": nan}
with self.assertRaisesRegex(
ValueError,
re.escape(
"variable 'x' is reserved for internal use of Function term, "
"please remove it from the map of variables: {'x': nan}"
),
ValueError,
re.escape(
"variable 'x' is reserved for internal use of Function term, "
"please remove it from the map of variables: {'x': nan}"
),
):
function_a.membership(0.0)
del function_a.variables["x"]
Expand Down Expand Up @@ -2290,7 +2290,7 @@ def test_function_parse(self) -> None:
"a+~b": "a b ~ +",
"~a*~b": "a ~ b ~ *",
"(sin(pi()/4) + cos(pi/4)) / (~sin(pi()/4) - ~cos(pi/4))": "pi 4.000 / sin pi 4.000 / cos + "
"pi 4.000 / sin ~ pi 4.000 / cos ~ - /",
"pi 4.000 / sin ~ pi 4.000 / cos ~ - /",
}
for infix, postfix in infix_postfix.items():
self.assertEqual(postfix, fl.Function.parse(infix).postfix())
Expand Down
18 changes: 9 additions & 9 deletions tests/test_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
from unittest.mock import MagicMock

import numpy as np
from typing_extensions import Self

import fuzzylite as fl
from fuzzylite.types import Self
from tests.assert_component import BaseAssert

T_Variable = TypeVar("T_Variable", bound=fl.Variable)
Expand Down Expand Up @@ -381,14 +381,14 @@ class TestOutputVariable(unittest.TestCase):
"""Test the output variable."""

def output_variable(
self,
enabled: bool = True,
name: str = "name",
description: str = "description",
minimum: float = -1.0,
maximum: float = 1.0,
default_value: float = fl.nan,
terms: list[fl.Term] | None = None,
self,
enabled: bool = True,
name: str = "name",
description: str = "description",
minimum: float = -1.0,
maximum: float = 1.0,
default_value: float = fl.nan,
terms: list[fl.Term] | None = None,
) -> fl.OutputVariable:
"""Create an output variable."""
return fl.OutputVariable(
Expand Down

0 comments on commit 3e81b7f

Please sign in to comment.