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

Create a CLI for connecting to a beamline #519

Merged
merged 21 commits into from
May 23, 2024
Merged

Conversation

callumforrester
Copy link
Contributor

Fixes #506

Instructions to reviewer on how to test:

  1. Run unit tests
  2. Run CLI system tests against all beamlines

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

@callumforrester callumforrester force-pushed the cli-system-tests branch 2 times, most recently from f3c2bfe to dc2d361 Compare May 13, 2024 10:35
Comment on lines 1 to 15
ALL_BEAMLINES: set[str] = {
"i03",
"i04",
"i04_1",
"i20_1",
"i22",
"i23",
"i24",
"p38",
"p45",
}
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 list of all beamline modules was previously maintained in the tests directory. It has been moved here so the CLI can reuse it.

I'm not sure how much I like maintaining a list of all beamline modules as it seems prone to error. The advantage is that typing dodal connect --help will include a list of beamlines you can connect to.

The alternatives are some fancy auto-detection of beamline modules, perhaps by finding all modules in dodal.beamlines that match a pattern or simply parsing any string the user enters and printing an error message if it's not a beamline.

I dislike the first because baking in beamline naming conventions has tended to lead to trouble in the past.

Copy link
Contributor

Choose a reason for hiding this comment

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

We could move _device_helpers.py etc. into some other location and just have a convention that only beamline modules live in beamlines. Then we can just auto-detect based on all the module names in that folder?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I felt that was worth its own PR: #544

src/dodal/cli.py Outdated


@main.command(name="connect")
@click.argument("beamline", type=click.Choice(list(ALL_BEAMLINES)), required=True)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Passing the beamline module in as an argument may be confusing in cases where it conflicts with the ${BEAMLINE} environment variable. However, in some cases the two are intentionally different. For example if running against s03 you load the i03 beamline module but with BEAMLINE=s03, so ${BEAMLINE} and the beamline module are two separate things with the same name and the same value in lots of cases, which seems a bit confusing. Not sure if it's worth tackling here or raising another issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could we default to using ${BEAMLINE} (which will be the case for 90%) of our users then bomb out if it's not set?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Except for i04-1, say, ${BEAMLINE} is i04-1 and the beamline module is i04_1, so I think they are the same in much less than 90% given that we already have two branchlines in dodal

Copy link
Contributor

Choose a reason for hiding this comment

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

Yh, you're right, let's just require 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.

I think it's still confusing given #519 (comment)

Some other options are:

  • Completely remove the ${BEAMLINE} variable from dodal, base everything on the beamline module
  • Have s03 as some kind of profile for i03 rather than base on the environment variable so you could do something like dodal connect --profile tickit i03, that would also be a good solution to Automatically keep I22 and P38 in sync #502

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, we then just move to solution 2 eventually as part of #502

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DominicOram I think I've probably misunderstood this because what I've done is the same thing again. I made it so you can type:

dodal connect i04-1

which will try to connect to s04-1 or

export BEAMLINE=i04-1
dodal connect

which try to connect to i04. That feels about as confusing and probably not what you had in mind.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have just thought of another requirement: the training rigs. They are all identical so should have one dodal module (I believe @paula-mg has prototyped one) and rely on ${BEAMLINE} or similar to differentiate.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I wasn't clear my suggestion is literally to do os.environ["BEAMLINE"] = beamline inside connect

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, also works for the training rig case

@callumforrester callumforrester marked this pull request as ready for review May 13, 2024 11:54
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. Code looks good but it doesn't behave exactly how I would expect. If I do dodal connect i03 it attempts to connect to s03 rather than i03. I'm also not convinced that it tries to connect to subsequent devices after the first failure. Additionally:

  • Could you add a line to the README that let's people know this exists?
  • I guess we can now remove all the test_XXX_system.pys?

@callumforrester
Copy link
Contributor Author

@DominicOram makes sense, the dodal connect i03 behaviour mirrors the i03 system tests, which try to connect to s03 by default unless ${BEAMLINE} is i03. I agree its confusing, which is why I was hoping for a better solution for #519 (comment)

@callumforrester
Copy link
Contributor Author

@DominicOram re: connecting to subsequent devices after the first failure: This is an issue in general with make_all_devices, hopefully one that @ZohebShaikh will solve as part of DiamondLightSource/blueapi#444

@callumforrester
Copy link
Contributor Author

CI failure should be fixed by #544

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. I think we need to fix the simulated beamlines being used so doing the os.environ["BEAMLINE"] = beamline is a Must unless you have a cleaner solution.

As I said before, can you remove the test_iXX_system.py files please?

Comment on lines +23 to +27
# On any workstation:
dodal connect <BEAMLINE>

# On a beamline workstation, this should suffice:
dodal connect ${BEAMLINE}
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: Sorry to scope creep a bit can we add this to the PR template while it's not in CI. As a reviewer it's basically the first thing I run and a lot of the time it fails.

src/dodal/cli.py Outdated

module_name = module_name_for_beamline(beamline)

from bluesky import RunEngine
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Does pylance not give you an error here about RunEngine not being exported from bluesky? I have to use from bluesky.run_engine import RunEngine to fix

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting, yes it does, even though RunEngine is exported from the top level: https://github.com/bluesky/bluesky/blob/27ca36cc60b718ad3f2f2bb343b1d086aec77708/src/bluesky/__init__.py#L4

I suspect pylance is only looking for __all__, will change it to reduce the nasty red lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also unsure why I'm doing the import inside the function, will change that too

src/dodal/cli.py Outdated


@main.command(name="connect")
@click.argument("beamline", type=click.Choice(list(ALL_BEAMLINES)), required=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I wasn't clear my suggestion is literally to do os.environ["BEAMLINE"] = beamline inside connect

@callumforrester
Copy link
Contributor Author

As I said before, can you remove the test_iXX_system.py files please?

Whoops, sorry!

@callumforrester callumforrester force-pushed the cli-system-tests branch 2 times, most recently from 24d7d98 to 4423626 Compare May 22, 2024 11:50
Comment on lines +36 to +37
# We need to mock the environment because the CLI edits it and this could break other
# tests
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Setting os.environ["BEAMLINE"] caused unintended side effects, will make an issue to find a better way

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 in #569

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! Minor nit-picks in code but otherwise good. I Tested a few of the beamlines. The _1 beamlines are broken for a different reason I think (#570) but others passed.

src/dodal/beamlines/__init__.py Outdated Show resolved Hide resolved
src/dodal/cli.py Outdated

module_name = module_name_for_beamline(beamline)

RE = RunEngine() # noqa: F841
Copy link
Contributor

Choose a reason for hiding this comment

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

Could: A comment here about why we need to make a RE would be good. Also do we actually need to assign it? Just RunEngine() works fine right, then we can remove the noqa?


RE = RunEngine() # noqa: F841

devices = make_all_devices(
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Would be nice if we could print something just before this saying that it's started and will take some time. The i03 ones take ~30s so not obvious it hasn't just hung.

@callumforrester callumforrester merged commit e5efc4e into main May 23, 2024
11 checks passed
@callumforrester callumforrester deleted the cli-system-tests branch May 23, 2024 08:04
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.

Connection test utility for each beamline
2 participants