Source code for dodal.beamlines
import importlib.util
from collections.abc import Iterable, Mapping
from functools import lru_cache
from pathlib import Path
# Where beamline names (per the ${BEAMLINE} environment variable don't always
# match up, we have to map between them bidirectionally). The most common use case is
# beamlines with a "-"" in the name such as "i20-1", which is not valid in a Python
# module name. Add any new beamlines whose name differs from their module name to this
# dictionary, which maps ${BEAMLINE} to dodal.beamlines.<MODULE NAME>
_BEAMLINE_NAME_OVERRIDES = {
"i13-1": "i13_1",
"i20-1": "i20_1",
"s03": "i03",
"p46": "training_rig",
"p47": "training_rig",
"p48": "training_rig",
"p49": "training_rig",
}
[docs]
def all_beamline_modules() -> Iterable[str]:
"""
Get the names of all importable modules in beamlines
Returns:
Iterable[str]: Generator of beamline module names
"""
# This is done by inspecting file names rather than modules to avoid
# premature importing
spec = importlib.util.find_spec(__name__)
if spec is not None:
assert spec.submodule_search_locations
search_paths = [Path(path) for path in spec.submodule_search_locations]
for path in search_paths:
for subpath in path.glob("**/*"):
if (
subpath.name.endswith(".py")
and subpath.name != "__init__.py"
and ("__pycache__" not in str(subpath))
):
yield subpath.with_suffix("").name
else:
raise KeyError(f"Unable to find {__name__} module")
[docs]
def all_beamline_names() -> Iterable[str]:
"""
Get the names of all beamlines as per the ${BEAMLINE} environment variable
Returns:
Iterable[str]: Generator of beamline names that dodal supports
"""
inverse_mapping = _module_name_overrides()
for module_name in all_beamline_modules():
yield from inverse_mapping.get(module_name, set()).union({module_name})
@lru_cache
def _module_name_overrides() -> Mapping[str, set[str]]:
"""
Get the inverse of _BEAMLINE_NAME_OVERRIDES so that modules can be mapped back to
beamlines. _BEAMLINE_NAME_OVERRIDES is expected to be a constant so the return
value is cached.
Returns:
Mapping[str, set[str]]: A dictionary mapping the name of a dodal module to the
set of beamlines it supports.
"""
inverse_mapping: dict[str, set[str]] = {}
for beamline, module in _BEAMLINE_NAME_OVERRIDES.items():
inverse_mapping[module] = inverse_mapping.get(module, set()).union({beamline})
return inverse_mapping
[docs]
def module_name_for_beamline(beamline: str) -> str:
"""
Get the module name for a particular beamline, it may differ from the beamline
name e.g. i20-1 -> i20_1
Args:
beamline: The beamline name as per the ${BEAMLINE} environment variable
Returns:
str: The importable module name
"""
return _BEAMLINE_NAME_OVERRIDES.get(beamline, beamline)