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

Isolated device factory #841

Merged
merged 15 commits into from
Oct 17, 2024
Merged

Isolated device factory #841

merged 15 commits into from
Oct 17, 2024

Conversation

DiamondJoseph
Copy link
Contributor

@DiamondJoseph DiamondJoseph commented Oct 14, 2024

Fixes #483

This is a re-implementation of #597 isolated to just the changes necessary to implement the @device_factory() decorator and have functions decorated with that decorator picked up by make_all_devices: respecting any configuration passed into the decorator.

NB: this is also required for blueapi #647

Instructions to reviewer on how to test:

  1. System test the i22 beamline to ensure that devices are instantiated, connected and named appropriately.

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}

Copy link

codecov bot commented Oct 14, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 95.19%. Comparing base (9e12af0) to head (9030d80).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #841      +/-   ##
==========================================
+ Coverage   95.12%   95.19%   +0.07%     
==========================================
  Files         120      120              
  Lines        4899     4976      +77     
==========================================
+ Hits         4660     4737      +77     
  Misses        239      239              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@DiamondJoseph DiamondJoseph marked this pull request as ready for review October 15, 2024 12:29
@DiamondJoseph DiamondJoseph requested review from coretl and removed request for coretl October 15, 2024 12:29
@callumforrester
Copy link
Contributor

I don't necessarily expect parallel connect to be implemented here but do we have tickets for achieving it?

@DiamondJoseph
Copy link
Contributor Author

DiamondJoseph commented Oct 16, 2024

I don't necessarily expect parallel connect to be implemented here but do we have tickets for achieving it?

for blueapi there's DiamondLightSource/blueapi#440
There should probably be one for dodal connect (and async that by default) when more beamlines are able to make use of it.

Copy link
Contributor

@stan-dot stan-dot left a comment

Choose a reason for hiding this comment

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

nice functools use

Copy link
Contributor

@DominicOram DominicOram left a comment

Choose a reason for hiding this comment

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

Great, thank you!

Some comments in code, mostly minor. I think a few more tests would also be good. e.g. we can test (assuming these are all desired behavior?):

  • A device gets renamed if called again with a different name
  • If we call with connect=False, mock=True we can then call again with mock=False

Additionally I think there's a potential pitfall in:

dcm(mock=True)
.... # Lots of code
dcm() # This now fails because it tries to turn the cached mock one into a real one

I'm not 100% sure if this is expected or if you would rather give the cached mocked one, maybe with a warning. We should at least document it but can do so in #780.

src/dodal/utils.py Outdated Show resolved Hide resolved
src/dodal/utils.py Outdated Show resolved Hide resolved
src/dodal/utils.py Outdated Show resolved Hide resolved
src/dodal/utils.py Outdated Show resolved Hide resolved
src/dodal/utils.py Show resolved Hide resolved
Copy link
Contributor

@DominicOram DominicOram left a comment

Choose a reason for hiding this comment

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

Thanks. I'm still a little concerned about the not 100% intuitive behavior of calling the factory twice with different permutations of connect/mock but I thin we can document/fix that later.

@DiamondJoseph
Copy link
Contributor Author

Assuming these are all desired behavior?

@coretl for comments?

* A device gets renamed if called again with a different name

A device can be renamed after having a name, so I think it should be allowed. Currently the device_factory name is only used if the device is currently unnamed.

* If we call with `connect=False, mock=True` we can then call again with `mock=False`

Only when connect is called is the device being mock or not considered. Calling with connect=False, mock=True then later connecting with mock=False would connect to the real signal backend.

Additionally I think there's a potential pitfall in:

dcm(mock=True)
.... # Lots of code
dcm() # This now fails because it tries to turn the cached mock one into a real one

Ophyd-async throws an exception if you try and connect a 2nd time with a different value of mock.
. I will amend to cache the value of mock after connect has been called at least one, and defer to it rather than the mock value set up with the decorator, so that we can still try and explicitly connect to [non-]mock, but will throw the exception only when we do so.

@DominicOram
Copy link
Contributor

DominicOram commented Oct 17, 2024

I will amend to cache the value of mock after connect has been called at least one, and defer to it rather than the mock value set up with the decorator, so that we can still try and explicitly connect to [non-]mock, but will throw the exception only when we do so.

I'm not even sure that is the best answer either. You then end up with the above code connecting you to a mock when you actually want a real device and potentially you fail to realise. I'm not sure there's a good solution here. I think the best thing to do is just document that calling the factory multiple times with different arguments can lead to odd behavior and to be careful.

@callumforrester
Copy link
Contributor

I agree there is no good solution to be honest, caching singletons is hard to do without some hidden magic. Maybe add more logging (but in a separate change).

@DiamondJoseph DiamondJoseph merged commit 0ba531c into main Oct 17, 2024
18 checks passed
@DiamondJoseph DiamondJoseph deleted the isolated-device-factory branch October 17, 2024 09:51
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 this pull request may close these issues.

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