Skip to content

Commit

Permalink
Allow aliased or extended builtin imports in device modules
Browse files Browse the repository at this point in the history
- Closes #56
  • Loading branch information
DiamondJoseph committed May 24, 2023
1 parent 7122c0b commit 8e3c7bb
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
7 changes: 5 additions & 2 deletions src/dodal/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,11 @@ def _is_device_skipped(func: Callable[..., Any]) -> bool:


def _is_device_factory(func: Callable[..., Any]) -> bool:
return_type = signature(func).return_annotation
return _is_device_type(return_type)
try:
return_type = signature(func).return_annotation
return _is_device_type(return_type)
except ValueError:
return False


def _is_device_type(obj: Type[Any]) -> bool:
Expand Down
47 changes: 47 additions & 0 deletions tests/fake_beamline_misbehaving_builtins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from typing import TypedDict

from ophyd.utils import DisconnectedError
from math import hypot, log


"""
Some builtins (e.g. dict, Exception), types that extend
them, and aliases for them, do not have signature information.
PEP-8 recommends being conservative with adding typing information
to builtins and the core Python library, so this may change slowly.
This beamline uses some types or constructions that are known to
cause issue but that could conceivably be used in a beamline file.
- Importing specific exceptions
- Importing functions from builtins, including math
- Aliasing builtins, including dict
- Defining a class that extends TypedDict (e.g. for parameters)
"""


def not_a_device() -> None:
"""
Importing DisconnectedError is enough to cause issue, but we
use it here to prevent linting from removing it from the imports.
"""
raise DisconnectedError()


def also_not_a_device() -> float:
"""
log and hypot both do not have signatures.
Not required to actually be used, importing is enough.
"""
return log(hypot(0, 0))


a = dict
b = Exception


class B(TypedDict):
"""
Causes issue only if a class that extends TypedDict exists.
"""
foo: int
6 changes: 6 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ def test_get_hostname() -> None:
assert get_hostname() == "a"


def test_no_signature_builtins_not_devices() -> None:
import tests.fake_beamline_misbehaving_builtins as fake_beamline
devices = make_all_devices(fake_beamline)
assert not devices


def device_a() -> Readable:
return MagicMock()

Expand Down

0 comments on commit 8e3c7bb

Please sign in to comment.