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

make device factory decorator #597

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

stan-dot
Copy link
Contributor

@stan-dot stan-dot commented Jun 5, 2024

Fixes #483

Instructions to reviewer on how to test:

  1. Do thing run i22 beamline
  2. Confirm lazy loading is possible

Checks for reviewer

  • Would the PR title make sense to a scientist on a set of release notes
  • If a new device has been added does it follow the standards
  • If changing the API for a pre-existing device, ensure that any beamlines using this device have updated their Bluesky plans accordingly
  • Have the connection tests for the relevant beamline(s) been run via dodal connect ${BEAMLINE}

@stan-dot stan-dot self-assigned this Jun 5, 2024
@stan-dot stan-dot requested a review from coretl June 5, 2024 16:22
@stan-dot stan-dot added documentation Improvements or additions to documentation enhancement New feature or request python Pull requests that update Python code labels Jun 5, 2024
@stan-dot stan-dot force-pushed the 483-make-device_factory-decorator-to-ease-making-and-connecting-ophyd-async-devices branch from 94124b4 to 27c1b79 Compare June 7, 2024 08:12
Copy link
Collaborator

@coretl coretl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea if the rest of the code is right until some tests are written...

src/dodal/beamlines/i22.py Outdated Show resolved Hide resolved
@coretl
Copy link
Collaborator

coretl commented Jun 7, 2024

To clarify, the code in the original ticket is an idea, but has never been run or tests. It is expected that it is wrong in some way, and writing tests to exercise it will reveal how it is wrong...

@stan-dot stan-dot changed the title Initial draft changes make device factory decorator Jun 10, 2024
@stan-dot stan-dot force-pushed the 483-make-device_factory-decorator-to-ease-making-and-connecting-ophyd-async-devices branch 3 times, most recently from f2ad915 to fb5e142 Compare June 12, 2024 14:29
@stan-dot stan-dot force-pushed the 483-make-device_factory-decorator-to-ease-making-and-connecting-ophyd-async-devices branch 4 times, most recently from 26368ca to 6cb1db6 Compare June 20, 2024 14:14
@stan-dot
Copy link
Contributor Author

stan-dot commented Jun 20, 2024

do we want to add 'skip device' to the factory too?

we could have just one decorator

@coretl
Copy link
Collaborator

coretl commented Jun 21, 2024

do we want to add 'skip device' to the factory too?

we could have just one decorator

This is a question for @callumforrester and @DominicOram. I don't know what a skipped device actually is? If we have a decorator here, then maybe we could "skip" it by omitting the decorator?

@DominicOram
Copy link
Contributor

skip was designed to let you provide logic on when to not instantiate a device. This is useful for:

  • Running the i03 devices against s03, where not all the devices are simulated
  • Running the i03 devices from a workstation, where we do not have PVA access to the beamline

@stan-dot
Copy link
Contributor Author

it's an architectural question. We can have all the logic that belongs to 'making device class instances' inside a bunch of nested decorators that need to be in right order. OR we can have 1 factory class that accepts a dictionary of features (lazy, mock, skip, directory provicder, post-create script) in one place.

@coretl
Copy link
Collaborator

coretl commented Jun 21, 2024

it's an architectural question. We can have all the logic that belongs to 'making device class instances' inside a bunch of nested decorators that need to be in right order. OR we can have 1 factory class that accepts a dictionary of features (lazy, mock, skip, directory provicder, post-create script) in one place.

I have a weak preference for a single decorator, but defer to @callumforrester and @DominicOram for a decision

@DominicOram
Copy link
Contributor

Single decorator works for me.

@stan-dot
Copy link
Contributor Author

ok I'll prepare a proof of concept for a single decorator device_factory with some (hopefully) sensible default args so that we can put the least props every time.

@stan-dot stan-dot force-pushed the 483-make-device_factory-decorator-to-ease-making-and-connecting-ophyd-async-devices branch from 6cb1db6 to 49e3bd2 Compare June 25, 2024 15:27
@stan-dot
Copy link
Contributor Author

@coretl please checkout the stuff in here

@stan-dot
Copy link
Contributor Author

stan-dot commented Jun 26, 2024

device_factory = cast(Callable[..., T], make_fake_device(device_factory))

beamline_utils.py 180

but that is inside ophyd, not sure how it works for ophyd-async

@stan-dot stan-dot force-pushed the 483-make-device_factory-decorator-to-ease-making-and-connecting-ophyd-async-devices branch from 0ecf386 to 656f918 Compare June 27, 2024 08:13
@stan-dot stan-dot force-pushed the 483-make-device_factory-decorator-to-ease-making-and-connecting-ophyd-async-devices branch from e436ef6 to f5a3fcf Compare August 23, 2024 08:25
@stan-dot
Copy link
Contributor Author

todos:

  1. help(device) make it comprehensive
  2. docs on top of i22.py
  3. consider the arguments visibility question

@stan-dot
Copy link
Contributor Author

@callumforrester from the blueapi perspective is the feature set enough (nonwithstanding the documentation and testing part, just the API exposed to blueapi)?

@stan-dot stan-dot force-pushed the 483-make-device_factory-decorator-to-ease-making-and-connecting-ophyd-async-devices branch from 16bfb79 to 3f9227f Compare August 27, 2024 10:25
Copy link
Contributor

@callumforrester callumforrester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stan-dot, apologies for not looking at this for a while. See DiamondLightSource/blueapi#440 for blueapi's requirements.

Does this API allow me to ask dodal for a list of all device factory functions for a particular beamline?

Having collected them all, how do I connect them in parallel? Or is that for a later PR?

Tagging @coretl in case he can help.

CONTROLLERS: dict[str, DeviceInitializationController] = {}


def instantiation_behaviour(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: Apologies if there's already been a discussion around it, but can we change this name? I'm concerned because _behaviour is a redundant suffix (see point 8 here) and because it didn't make sense to me until I read a function it was decorating. Some alternatives:

  1. device_instantiation
  2. device_factory
  3. device_configuration
  4. device_singleton

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

device_instantiation is bad for a function name here, as device_instantiation is an event that happens whenever we call the waxs() (where waxs = some_device), so a function with that name is confusing
factory is technically true but it's an oop statement fitting for a class, but here it is a decorator
device_configuration is underspecified - this is specifically device_iniitalization_configuration
singleton is inaccurate as it does not prevent by itself more than 1 instance afaik

add_instantiation_behavior_to_device would be my suggestion.
Zen of Python says:

description="AVT Mako G-507B",
distance=(-1.0, "m"),
),
metadata_holder=metadata_holder,
directory_provider=get_directory_provider(),
)


@skip_device()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could: Is @instantiation_behaviour now rich enough that we can replace calls to @skip_device with it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that is the premise of the function signature, not 100% sure about the implementation details still


def __call__(
self,
connect=False,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
connect=False,
connect: bool = False,

CONTROLLERS[self.factory.__name__] = self
self.device = None

def see_if_device_is_in_cache(self) -> AnyDevice | None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: I would prefer more conventional terminology here:

Suggested change
def see_if_device_is_in_cache(self) -> AnyDevice | None:
def get_device_if_cached(self) -> AnyDevice | None:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will implement suggestions tomorrow

Comment on lines +115 to +131
beamline_prefix = "example:"


@instantiation_behaviour(
default_use_mock_at_connection=True, default_timeout_for_connect=10
)
def new_detector_xyz():
"""Create an XYZ detector with specific settings."""
return XYZDetector(name="det1", prefix=f"{beamline_prefix}xyz:")


@instantiation_behaviour(
eager=True, default_use_mock_at_connection=True, default_timeout_for_connect=10
)
def detector_xyz_variant():
"""Create an XYZ detector with specific settings."""
return XYZDetector(name="det2-variant", prefix=f"{beamline_prefix}xyz:")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could: Could the example module be in its own file? I'd find that more readable.

Copy link
Contributor Author

@stan-dot stan-dot Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure! any path and name suggestions @callumforrester ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request python Pull requests that update Python code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make device_factory decorator to ease making and connecting ophyd-async Devices
6 participants