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

Reinstate DeviceInitializationController #881

Merged
merged 14 commits into from
Nov 25, 2024

Conversation

callumforrester
Copy link
Contributor

Fixes #878

Instructions to reviewer on how to test:

  1. Run unit tests
  2. Run system tests for I22
  3. Run system tests for at least 1 other beamline

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}

@callumforrester callumforrester force-pushed the 878-reinstate-device-initialization-controller branch 3 times, most recently from b492c0c to e47b9f7 Compare November 6, 2024 14:37
Copy link

codecov bot commented Nov 6, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.03%. Comparing base (a2e93ed) to head (35d6808).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #881      +/-   ##
==========================================
+ Coverage   95.98%   96.03%   +0.04%     
==========================================
  Files         136      136              
  Lines        5561     5623      +62     
==========================================
+ Hits         5338     5400      +62     
  Misses        223      223              

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


🚨 Try these New Features:

mock: bool,
skip: SkipType,
):
self._factory: Callable[[], D] = functools.lru_cache(factory)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should behave in a similar way to the previous cache implementation, but we now have a lot of layers of caching:

device-caching(1)

3 caches is not ideal, especially for 2 use cases. It may be that we have to leave it like this and remove it once device_instantiation is gone because each use case routes to difference caches in different ways:

blueapi python shell (manual call) python shell (calling make_all_devices)
via device_instantiation BlueskyContext.devices ACTIVE_DEVICES ACTIVE_DEVICES
via device_factory BlueskyContext.devices DeviceInitializationController.lru_cache ACTIVE_DEVICES

We should think about where to cache things long-term. A single place would be ideal, thoughts welcome.

Copy link
Contributor

Choose a reason for hiding this comment

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

I can't see where make_all_devices uses ACTIVE_DEVICES other than it being called by device_instantiation? So is it not:

blueapi python shell (manual call) python shell (calling make_all_devices)
via device_instantiation BlueskyContext.devices ACTIVE_DEVICES ACTIVE_DEVICES
via device_factory BlueskyContext.devices DeviceInitializationController.lru_cache DeviceInitializationController.lru_cache

In which case the two caches are just the old one and the new one and I think we can then just remove the need for the new device factory to put anything into ACTIVE_DEVICES?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is where it uses ACTIVE_DEVICES, albeit in a write-only capacity:

controller.add_callback(lambda device: cache_device(device, factory.__name__))

So maybe you're right, can we get away without that and have a clean separation?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I think there's no need for the new instantiation method to write to 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.

Done, although I had to change this test so it no longer relies on ACTIVE_DEVICES, see what you think

@callumforrester callumforrester marked this pull request as ready for review November 6, 2024 15:17
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, some comments in code. Additionally, I don;t think the system tests are working. When I run dodal connect i22 it passes but if I change a device to be the wrong PV it still passes, I would expect it to fail

Comment on lines 125 to 137
crystal_1_metadata = CrystalMetadata(
usage="Bragg",
type="silicon",
reflection=(1, 1, 1),
d_spacing=(3.13475, "nm"),
)
crystal_2_metadata = CrystalMetadata(
usage="Bragg",
type="silicon",
reflection=(1, 1, 1),
d_spacing=(3.13475, "nm"),
)
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 think the make_crystal_metadata_from_material is cleaner

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch

mock: bool,
skip: SkipType,
):
self._factory: Callable[[], D] = functools.lru_cache(factory)
Copy link
Contributor

Choose a reason for hiding this comment

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

I can't see where make_all_devices uses ACTIVE_DEVICES other than it being called by device_instantiation? So is it not:

blueapi python shell (manual call) python shell (calling make_all_devices)
via device_instantiation BlueskyContext.devices ACTIVE_DEVICES ACTIVE_DEVICES
via device_factory BlueskyContext.devices DeviceInitializationController.lru_cache DeviceInitializationController.lru_cache

In which case the two caches are just the old one and the new one and I think we can then just remove the need for the new device factory to put anything into ACTIVE_DEVICES?

assert mirror.connect.call_count == 1 # type: ignore


def test_multiple_layers_of_lru_caching_does_not_affect_device():
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: It's not clear why this testing the multiple layers of cache is needed, would suggest a docstring as to why it's important to test

assert mirror.connect.call_count == 1 # type: ignore


def test_multiple_layers_of_lru_caching_does_not_affect_device():
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 think it would be good to test that the returned devices are the same without having the extra cache here too

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's implicitly covered by test_device_factory_can_rename but I think you may be right that it deserves its own test

@callumforrester
Copy link
Contributor Author

@DominicOram I'm aware the system tests are unhappy, should have commented here, sorry about that.

@DominicOram
Copy link
Contributor

DominicOram commented Nov 11, 2024

@DominicOram I'm aware the system tests are unhappy, should have commented here, sorry about that

No worries, the Instructions to test imply they are ok though. Will this be addressed in another issue or part of this one?

@callumforrester
Copy link
Contributor Author

It will be addressed here, I don't want to merge this without addressing this problem, I just thought it had already been fixed in #858, but apparently not...

@callumforrester callumforrester force-pushed the 878-reinstate-device-initialization-controller branch from ed41f3b to 412a4c7 Compare November 11, 2024 14:41
_, _, exceptions = module_and_devices_for_beamline
if len(exceptions) > 0:
raise NotConnected(exceptions)
# Pass test if there were no exceptions
Copy link
Contributor

Choose a reason for hiding this comment

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

Could: This change is fine by me. You could also still check follows_bluesky_protocols for all returned devices but I'm not sure it gives you loads. If we're not using follows_bluesky_protocols now though we should remove it.

@callumforrester
Copy link
Contributor Author

It will be addressed here, I don't want to merge this without addressing this problem, I just thought it had already been fixed in #858, but apparently not...

@DominicOram I've changed my mind about this having realised that this bug also affects device_instantiation in main (albeit less), see #864.

I'm going to take over and finish #865 to address.

@callumforrester callumforrester force-pushed the 878-reinstate-device-initialization-controller branch 2 times, most recently from ce4b3c8 to f7a901f Compare November 20, 2024 15:55
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.

I found a few issues from running dodal connect i22 and comparing to main

fake_with_ophyd_sim,
)
@device_factory()
def linkam() -> Linkam3:
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: The linkam was previously skipped, should it not still be?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question, it was skipped back when make_all_devices raised an exception if any device couldn't connect. Now we've instead got it to return an exception and let the user handle it, it matters less. I will restore the skip though as removing it is out of scope and can be handled in another PR.

]
assert (
len(devices_not_following_bluesky_protocols) == 0
), f"{devices_not_following_bluesky_protocols} do not follow blueesky protocols"
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit:

Suggested change
), f"{devices_not_following_bluesky_protocols} do not follow blueesky protocols"
), f"{devices_not_following_bluesky_protocols} do not follow bluesky protocols"

)
@device_factory()
def linkam() -> Linkam3:
return Linkam3(prefix=f"{PREFIX.beamline_prefix}-EA-TEMPC-05")
Copy link
Contributor

Choose a reason for hiding this comment

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

Could: I suspect we need a : after the prefix here. Hard to tell 100% as it doesn't connect either way and was previously being skipped so we would have missed it anyway

Suggested change
return Linkam3(prefix=f"{PREFIX.beamline_prefix}-EA-TEMPC-05")
return Linkam3(prefix=f"{PREFIX.beamline_prefix}-EA-TEMPC-05:")

@device_factory()
def hfm() -> FocusingMirror:
return FocusingMirror(
prefix=f"{PREFIX.beamline_prefix}|-OP-KBM-01:HFM:",
Copy link
Contributor

Choose a reason for hiding this comment

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

Must: Accidental | after the prefix here.

Suggested change
prefix=f"{PREFIX.beamline_prefix}|-OP-KBM-01:HFM:",
prefix=f"{PREFIX.beamline_prefix}-OP-KBM-01:HFM:",

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!

@callumforrester callumforrester force-pushed the 878-reinstate-device-initialization-controller branch from 88b5aa5 to 860b6bf Compare November 25, 2024 13:14
@callumforrester callumforrester force-pushed the 878-reinstate-device-initialization-controller branch from 860b6bf to 35d6808 Compare November 25, 2024 13:18
@DiamondJoseph DiamondJoseph merged commit a3cf0ec into main Nov 25, 2024
19 checks passed
@DiamondJoseph DiamondJoseph deleted the 878-reinstate-device-initialization-controller branch November 25, 2024 13:22
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.

Reinstate new device factory and its use for I22
3 participants