Skip to content

Commit

Permalink
Merge branch 'main' into 215_soft_signals
Browse files Browse the repository at this point in the history
  • Loading branch information
jsouter authored Apr 18, 2024
2 parents 5f551aa + 3e95942 commit e3d4b63
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 10 deletions.
25 changes: 16 additions & 9 deletions src/ophyd_async/epics/_backend/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ def get_supported_enum_class(
datatype: Optional[Type[Enum]],
pv_choices: Tuple[Any, ...],
) -> Type[Enum]:
if datatype:
if not issubclass(datatype, Enum):
raise TypeError(f"{pv} has type Enum not {datatype.__name__}")
if not issubclass(datatype, str):
raise TypeError(f"{pv} has type Enum but doesn't inherit from String")
choices = tuple(v.value for v in datatype)
if set(choices).difference(pv_choices):
raise TypeError(f"{pv} has choices {pv_choices}: not all in {choices}")
return Enum("GeneratedChoices", {x or "_": x for x in pv_choices}, type=str) # type: ignore
if not datatype:
return Enum("GeneratedChoices", {x or "_": x for x in pv_choices}, type=str) # type: ignore

if not issubclass(datatype, Enum):
raise TypeError(f"{pv} has type Enum not {datatype.__name__}")
if not issubclass(datatype, str):
raise TypeError(f"{pv} has type Enum but doesn't inherit from String")
choices = tuple(v.value for v in datatype)
if set(choices) != set(pv_choices):
raise TypeError(
(
f"{pv} has choices {pv_choices}, "
f"which do not match {datatype}, which has {choices}"
)
)
return datatype
58 changes: 58 additions & 0 deletions tests/epics/_backend/test_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from enum import Enum

import pytest

from ophyd_async.epics._backend.common import get_supported_enum_class


def test_given_a_non_enum_passed_to_get_supported_enum_then_raises():
with pytest.raises(TypeError):
get_supported_enum_class("", int, ("test",))


def test_given_an_enum_but_not_str_passed_to_get_supported_enum_then_raises():
class MyEnum(Enum):
TEST = "test"

with pytest.raises(TypeError):
get_supported_enum_class("", MyEnum, ("test",))


def test_given_pv_has_choices_not_in_supplied_enum_then_raises():
class MyEnum(str, Enum):
TEST = "test"

with pytest.raises(TypeError):
get_supported_enum_class("", MyEnum, ("test", "unexpected_choice"))


def test_given_supplied_enum_has_choices_not_in_pv_then_raises():
class MyEnum(str, Enum):
TEST = "test"
OTHER = "unexpected_choice"

with pytest.raises(TypeError):
get_supported_enum_class("", MyEnum, ("test",))


def test_given_no_supplied_enum_then_returns_generated_choices_enum_with_pv_choices():
enum_class = get_supported_enum_class("", None, ("test",))

assert isinstance(enum_class, type(Enum("GeneratedChoices", {})))
all_values = [e.value for e in enum_class] # type: ignore
assert len(all_values) == 1
assert "test" in all_values


def test_given_a_supplied_enum_that_matches_the_pv_choices_then_enum_type_is_returned():
class MyEnum(str, Enum):
TEST_1 = "test_1"
TEST_2 = "test_2"

enum_class = get_supported_enum_class("", MyEnum, ("test_1", "test_2"))

assert isinstance(enum_class, type(MyEnum))
all_values = [e.value for e in enum_class] # type: ignore
assert len(all_values) == 2
assert "test_1" in all_values
assert "test_2" in all_values
5 changes: 4 additions & 1 deletion tests/epics/test_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,10 @@ class EnumNoString(Enum):
(
BadEnum,
"enum",
"has choices ('Aaa', 'Bbb', 'Ccc'): not all in ('Aaa', 'B', 'Ccc')",
(
"has choices ('Aaa', 'Bbb', 'Ccc'), which do not match "
"<enum 'BadEnum'>, which has ('Aaa', 'B', 'Ccc')"
),
),
(int, "str", "has type str not int"),
(str, "float", "has type float not str"),
Expand Down

0 comments on commit e3d4b63

Please sign in to comment.