Skip to content

Migrate BeamlineParameters to use config server#1773

Open
jacob720 wants to merge 25 commits intomainfrom
mx_bluesky_1504_migrate_beamline_parameters_to_config_server
Open

Migrate BeamlineParameters to use config server#1773
jacob720 wants to merge 25 commits intomainfrom
mx_bluesky_1504_migrate_beamline_parameters_to_config_server

Conversation

@jacob720
Copy link
Contributor

@jacob720 jacob720 commented Dec 9, 2025

Fixes DiamondLightSource/mx-bluesky#1504

Required by DiamondLightSource/mx-bluesky#1511

Instructions to reviewer on how to test:

  1. Test beamline parameters files are not read from the file system in dodal

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}

@codecov
Copy link

codecov bot commented Jan 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.06%. Comparing base (a1bcbe9) to head (286a17c).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1773      +/-   ##
==========================================
+ Coverage   99.04%   99.06%   +0.01%     
==========================================
  Files         308      313       +5     
  Lines       11672    11720      +48     
==========================================
+ Hits        11561    11610      +49     
+ Misses        111      110       -1     

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jacob720 jacob720 marked this pull request as ready for review January 12, 2026 16:45
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, this looks good, some comments in code. This also means that we are now reliant on the config server so I think we need to do DiamondLightSource/mx-bluesky#478 before we put this on the beamline. Would you be able to pick that up and put in a meeting with Neil, Mark, Rob and Myself?

from dodal.log import LOGGER
from dodal.utils import get_beamline_name

BEAMLINE_PARAMETER_KEYWORDS = ["FB", "FULL", "deadtime"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: This list is no longer used, can we remove it?

)


def get_beamline_parameters(beamline_param_path: str | None = None):
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 is a bit of scope creep but the way we're doing this is a bit messy. I think we can do it like we do

def daq_configuration_path() -> str:
and load it in as part of the beamline file. If that makes sense? Can you either do here or make a new issue?

Copy link
Contributor Author

@jacob720 jacob720 Jan 20, 2026

Choose a reason for hiding this comment

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

This makes sense. So when devices need beamline parameters and before would have called get_beamline_parameters(), I'm guessing now they'd be passed in when the device is constructed.

How would this work when we need to get beamline parameters inside common plans? Or should these params always be attached to devices by that point?

Copy link
Contributor

Choose a reason for hiding this comment

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

So when devices need beamline parameters and before would have called get_beamline_parameters(), I'm guessing now they'd be passed in when the device is constructed.

Yes

How would this work when we need to get beamline parameters inside common plans? Or should these params always be attached to devices by that point?

Yh, that is a bit harder. I think we would need to have a look at it, which maybe means it should be in another issue

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe a similar thing can be done for the config server itself? So have a get_config_server() in every ixx.py that returns a config client set up for that beamline

return cls(params=dict(config_pairs))

@classmethod
def from_file(cls, path: str):
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 a little misleading that this is still called from_file when it's not reading directly from the file

@classmethod
def parse_value(cls, value: str):
return ast.literal_eval(value.replace("Yes", "True").replace("No", "False"))
config_server = ConfigServer(url="https://daq-config.diamond.ac.uk")
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: Can you pull the URL into a constant? From DiamondLightSource/mx-bluesky#478 (comment) it may be that we will need it to be beamline specific too

Comment on lines 175 to 179
print(contents)
if desired_return_type is str:
return contents
elif desired_return_type is dict:
print("return type is dict")
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: Remove print statements

elif desired_return_type is dict:
print("return type is dict")
return json.loads(contents)
elif issubclass(desired_return_type, ConfigModel): # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: As far as I can see we're never trying to return a ConfigModel so why do we need this bit? Or is it for later PRs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this is for later PRs. We either get a dict or a ConfigModel depending on what we request from the server, other config like LUTs or display config will be returned as a subclass of ConfigModel, this fixture emulates that

@jacob720 jacob720 force-pushed the mx_bluesky_1504_migrate_beamline_parameters_to_config_server branch from c87a30e to 3dbb881 Compare January 23, 2026 17:33
@jacob720 jacob720 requested a review from DominicOram January 26, 2026 09:59
@rtuck99 rtuck99 self-assigned this Feb 9, 2026
def _load_topup_configuration_from_properties_file() -> dict[str, Any]:
params = get_beamline_parameters()
return params.params
params = get_beamline_parameters(get_beamline_name("i03"))
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really like this practice that we have in the code of inserting arbitrary default beamline names into random bits of code. By removing the default from get_beamline_parameters() this has just spread it around more.

I think it would be better if we never assumed it anywhere in production code and instead took it from the BEAMLINE environment variable in a single function which we can patch out for unit tests.

Copy link
Contributor Author

@jacob720 jacob720 Feb 10, 2026

Choose a reason for hiding this comment

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

So basically remove the 'default' argument from get_beamline_name()?

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've had a quick go at doing this and it's looking like a big change, and I'm not 100% sure of the consequences, so I think we should pull it out into a new issue. For now, I'll make the default argument optional so that we don't have to arbitrarily decide on defaults.

# Nb this parameter is misleadingly named to confuse you
self.dcm_fixed_offset_mm = get_beamline_parameters(
daq_configuration_path + "/domain/beamlineParameters"
get_beamline_name("i03"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is undulator special, it's the only one that uses the extra parameter on get_beamline_parameters(), isn't it just getting the same beamline parameters file that everything else uses? The only other places it's used are tests.

I think we should drop the filename argument unless you can think of a good reason to keep it.

@jacob720 jacob720 requested a review from rtuck99 February 11, 2026 16:59


def test_get_beamline_parameters_works_with_no_environment_variable_set():
def test_get_beamline_parameters_errors_with_no_environment_variable_set():
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably best to do something like patch.dict(environ, {k: v for k, v in environ.items() if k != "BEAMLINE"}, clear=True) if only to avoid any possibility of strange downstream effects from mutating our environment (although we should hopefully be agnostic to this environment variable)

Copy link
Contributor

Choose a reason for hiding this comment

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

or perhaps even simpler use monkeypatch as you have used below



def test_get_beamline_parameters_works_with_no_environment_variable_set():
def test_get_beamline_parameters_errors_with_no_environment_variable_set():
Copy link
Contributor

Choose a reason for hiding this comment

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

This test doesn't actually do what it says on the tin - because we specify the beamline parameter it never errors.

Copy link
Contributor

@rtuck99 rtuck99 left a comment

Choose a reason for hiding this comment

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

Approved, subject to fixing test to cover the error condition, and minor observation about environment

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.

Migrate beamline paramaters to use the daq-config-server

3 participants

Comments