-
Notifications
You must be signed in to change notification settings - Fork 8
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
Conversation
f3c2bfe
to
dc2d361
Compare
src/dodal/beamlines/__init__.py
Outdated
ALL_BEAMLINES: set[str] = { | ||
"i03", | ||
"i04", | ||
"i04_1", | ||
"i20_1", | ||
"i22", | ||
"i23", | ||
"i24", | ||
"p38", | ||
"p45", | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this 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.py
s?
@DominicOram makes sense, the |
@DominicOram re: connecting to subsequent devices after the first failure: This is an issue in general with |
d314fc5
to
4395567
Compare
1fec9e4
to
4492d1b
Compare
CI failure should be fixed by #544 |
4492d1b
to
c99dc77
Compare
There was a problem hiding this 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?
# On any workstation: | ||
dodal connect <BEAMLINE> | ||
|
||
# On a beamline workstation, this should suffice: | ||
dodal connect ${BEAMLINE} |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
Whoops, sorry! |
24d7d98
to
4423626
Compare
# We need to mock the environment because the CLI edits it and this could break other | ||
# tests |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in #569
79519a8
to
d080cb3
Compare
d080cb3
to
151c6e8
Compare
There was a problem hiding this 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/cli.py
Outdated
|
||
module_name = module_name_for_beamline(beamline) | ||
|
||
RE = RunEngine() # noqa: F841 |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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.
Co-authored-by: Dominic Oram <[email protected]>
Fixes #506
Instructions to reviewer on how to test:
Checks for reviewer