Skip to content
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

Allow creation of a numpy array soft signal #505

Closed
DominicOram opened this issue Aug 2, 2024 · 1 comment · Fixed by #594
Closed

Allow creation of a numpy array soft signal #505

DominicOram opened this issue Aug 2, 2024 · 1 comment · Fixed by #594

Comments

@DominicOram
Copy link
Contributor

When I try and do this I get an error of:

ERROR:blueapi.worker.reworker:invalid converter for value of type <class 'numpy.ndarray'>
Traceback (most recent call last):
  File "/venv/lib/python3.11/site-packages/blueapi/worker/reworker.py", line 250, in _cycle
    self._current.task.do_task(self._ctx)
  File "/venv/lib/python3.11/site-packages/blueapi/worker/task.py", line 31, in do_task
    ctx.run_engine(func(**prepared_params.dict()))
  File "/venv/lib/python3.11/site-packages/bluesky/run_engine.py", line 918, in __call__
    plan_return = self._resume_task(init_func=_build_task)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/bluesky/run_engine.py", line 1057, in _resume_task
    raise exc
  File "/venv/lib/python3.11/site-packages/bluesky/run_engine.py", line 1687, in _run
    raise err
  File "/venv/lib/python3.11/site-packages/bluesky/run_engine.py", line 1547, in _run
    msg = self._plan_stack[-1].send(resp)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/blueapi-plugins/scratch/mx_bluesky/src/mx_bluesky/i04/thawing_plan.py", line 95, in thaw_and_center
    yield from _thaw_and_center()
  File "/venv/lib/python3.11/site-packages/bluesky/utils/__init__.py", line 1203, in dec_inner
    return (yield from plan)
            ^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/bluesky/preprocessors.py", line 408, in subs_wrapper
    return (yield from finalize_wrapper(_inner_plan(),
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/bluesky/preprocessors.py", line 535, in finalize_wrapper
    ret = yield from plan
          ^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/bluesky/preprocessors.py", line 406, in _inner_plan
    return (yield from plan)
            ^^^^^^^^^^^^^^^
  File "/blueapi-plugins/scratch/mx_bluesky/src/mx_bluesky/i04/thawing_plan.py", line 87, in _thaw_and_center
    yield from bps.monitor(oav.test_signal, name="oav")
  File "/venv/lib/python3.11/site-packages/bluesky/plan_stubs.py", line 146, in monitor
    return (yield Msg('monitor', obj, name=name, **kwargs))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/bluesky/run_engine.py", line 1607, in _run
    new_response = await coro(msg)
                   ^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/bluesky/run_engine.py", line 1950, in _monitor
    await current_run.monitor(msg)
  File "/venv/lib/python3.11/site-packages/bluesky/bundlers.py", line 392, in monitor
    await self._ensure_cached(obj)
  File "/venv/lib/python3.11/site-packages/bluesky/bundlers.py", line 207, in _ensure_cached
    await asyncio.gather(*coros)
  File "/venv/lib/python3.11/site-packages/bluesky/bundlers.py", line 337, in _cache_describe
    self._describe_cache[obj] = await maybe_await(obj.describe())
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/bluesky/utils/__init__.py", line 1852, in maybe_await
    return await ret
           ^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/ophyd_async/core/signal.py", line 41, in wrapper
    return await asyncio.wait_for(func(self, *args, **kwargs), self._timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/tasks.py", line 489, in wait_for
    return fut.result()
           ^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/ophyd_async/core/signal.py", line 195, in describe
    return {self.name: await self._backend.get_datakey(self.source)}
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/ophyd_async/core/soft_signal_backend.py", line 186, in get_datakey
    return self.converter.get_datakey(source, self._value, **self._metadata)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/ophyd_async/core/soft_signal_backend.py", line 60, in get_datakey
    dtype in primitive_dtypes
AssertionError: invalid converter for value of type <class 'numpy.ndarray'>

I can use a list to get round this but numpy arrays are valid as normal PV signal types and so should be valid here

@coretl
Copy link
Collaborator

coretl commented Aug 19, 2024

Might be fixed by #522

@coretl coretl closed this as completed in a30d8cd Oct 30, 2024
ZohebShaikh pushed a commit that referenced this issue Nov 14, 2024
Rewrite the type support, and use a plugin `Connector` architecture to support reconnection for PVI and Tango.

Fixes #472, fixes #562, fixes #535, fixes #505, fixes #373, fixes #601

Required for #551

Structure now read from `.value` rather than `.pvi`. Supported in FastCS. Requires at least PandABlocks-ioc 0.10.0
```python
from enum import Enum
class MyEnum(str, Enum):
    ONE = "one"
    TWO = "two"
from ophyd_async.core import StrictEnum
class MyEnum(StrictEnum):
    ONE = "one"
    TWO = "two"
```
```python
from ophyd_async.core import SubsetEnum
MySubsetEnum = SubsetEnum["one", "two"]
class MySubsetEnum(SubsetEnum):
    ONE = "one"
    TWO = "two"
```
```python
import numpy as np
x = epics_signal_rw(np.int32, "PV")
x = epics_signal_rw(int, "PV")
```
```python
import numpy as np
import numpy.typing as npt
x = epics_signal_rw(npt.NDArray[np.int32], "PV")
from ophyd_async.core import Array1D
x = epics_signal_rw(Array1D[np.int32], "PV")
```
```python
import numpy as np
import numpy.typing as npt
x = epics_signal_rw(npt.NDArray[np.str_], "PV")
from collections.abc import Sequence
x = epics_signal_rw(Sequence[str], "PV")
```
```python
fake_set_signal = SignalRW(MockSignalBackend(float))
fake_set_signal = soft_signal_rw(float)
await fake_set_signal.connect(mock=True)
```
```python
get_mock_put(driver.capture).assert_called_once_with(Writing.ON, wait=ANY, timeout=ANY)
get_mock_put(driver.capture).assert_called_once_with(Writing.ON, wait=ANY)
```
```python
class MyDevice(Device):
    def __init__(self, name: str = ""):
        self.signal, self.backend_put = soft_signal_r_and_setter(int)
class MyDevice(Device):
    def __init__(self, name: str = ""):
        self.signal, self.backend_put = soft_signal_r_and_setter(int)
        super().__init__(name=name)
```
The `Table` type has been suitable for everything we have seen so far, if you need an arbitrary `BaseModel` subclass then please make an issue
```python
class SourceDevice(Device):
    def __init__(self, name: str = ""):
        self.signal = soft_signal_rw(int)
        super().__init__(name=name)

class ReferenceDevice(Device):
    def __init__(self, signal: SignalRW[int], name: str = ""):
        self.signal = signal
        super().__init__(name=name)

    def set(self, value) -> AsyncStatus:
        return self.signal.set(value + 1)
from ophyd_async.core import Reference

class ReferenceDevice(Device):
    def __init__(self, signal: SignalRW[int], name: str = ""):
        self._signal_ref = Reference(signal)
        super().__init__(name=name)

    def set(self, value) -> AsyncStatus:
        return self._signal_ref().set(value + 1)
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants