Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions pyaml/common/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ def _class_exclusions(obj) -> set[str]:
return exclusions


def _properties(obj) -> dict[str, Any]:
def _properties(obj, exclusions: set[str] = frozenset()) -> dict[str, Any]:
# Excluded properties are skipped before evaluation: a getter that raises
# with str(self) in its message would otherwise re-enter the repr.
values: dict[str, Any] = {}
for cls in reversed(type(obj).__mro__):
for name, descriptor in vars(cls).items():
if name.startswith("_") or not isinstance(descriptor, property):
if name.startswith("_") or name in exclusions or not isinstance(descriptor, property):
continue
try:
values[name] = getattr(obj, name)
Expand All @@ -75,15 +77,15 @@ def _properties(obj) -> dict[str, Any]:
return values


def _fields(obj) -> dict[str, Any]:
def _fields(obj, exclusions: set[str] = frozenset()) -> dict[str, Any]:
custom_fields = getattr(obj, "_pyaml_repr_fields", None)
if custom_fields is not None:
try:
return custom_fields()
except Exception as error:
return {"value": _unavailable(error)}

values = _properties(obj)
values = _properties(obj, exclusions)
for name, value in vars(obj).items():
if not name.startswith("_"):
values.setdefault(name, value)
Expand Down Expand Up @@ -158,10 +160,10 @@ def _format_object(obj, depth: int, active: set[int], extra_exclusions: set[str]

active.add(id(obj))
try:
values = _fields(obj)
exclusions = _class_exclusions(obj)
if extra_exclusions:
exclusions.update(extra_exclusions)
values = _fields(obj, exclusions)
parts = []
for name, value in values.items():
if name.startswith("_") or name in exclusions or callable(value):
Expand Down
6 changes: 3 additions & 3 deletions pyaml/diagnostics/bpm/bpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def positions(self) -> ReadFloatArray:
If positions have not been attached
"""
if self._positions is None:
raise PyAMLException(f"{str(self)} has no attached positions")
raise PyAMLException(f"{self.name} has no attached positions")
return self._positions

@property
Expand All @@ -135,7 +135,7 @@ def offset(self) -> ReadWriteFloatArray:
If offset has not been attached
"""
if self._offset is None:
raise PyAMLException(f"{str(self)} has no attached offset")
raise PyAMLException(f"{self.name} has no attached offset")
return self._offset

@property
Expand All @@ -154,7 +154,7 @@ def tilt(self) -> ReadWriteFloatScalar:
If tilt has not been attached
"""
if self._tilt is None:
raise PyAMLException(f"{str(self)} has no attached tilt")
raise PyAMLException(f"{self.name} has no attached tilt")
return self._tilt

def attach(
Expand Down
4 changes: 2 additions & 2 deletions pyaml/magnet/cfm_magnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def strengths(self) -> abstract.ReadWriteFloatScalar:
"""
self.check_peer()
if self.__strengths is None:
raise PyAMLException(f"{str(self)} has no model that supports physics units")
raise PyAMLException(f"{self.name} has no model that supports physics units")
return self.__strengths

@property
Expand All @@ -250,7 +250,7 @@ def hardwares(self) -> abstract.ReadWriteFloatScalar:
"""
self.check_peer()
if self.__hardwares is None:
raise PyAMLException(f"{str(self)} has no model that supports hardware units")
raise PyAMLException(f"{self.name} has no model that supports hardware units")
return self.__hardwares

def set_energy(self, E: float):
Expand Down
4 changes: 2 additions & 2 deletions pyaml/magnet/magnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def strength(self) -> abstract.ReadWriteFloatScalar:
"""
self.check_peer()
if self.__strength is None:
raise PyAMLException(f"{str(self)} has no model that supports physics units")
raise PyAMLException(f"{self.name} has no model that supports physics units")
return self.__strength

@property
Expand All @@ -94,7 +94,7 @@ def hardware(self) -> abstract.ReadWriteFloatScalar:
"""
self.check_peer()
if self.__hardware is None:
raise PyAMLException(f"{str(self)} has no model that supports hardware units")
raise PyAMLException(f"{self.name} has no model that supports hardware units")
return self.__hardware

@property
Expand Down
4 changes: 2 additions & 2 deletions pyaml/magnet/serialized_magnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ def strength(self) -> abstract.ReadWriteFloatScalar:
"""
self.check_peer()
if self.__strengths is None:
raise PyAMLException(f"{str(self)} has no model that supports physics units")
raise PyAMLException(f"{self.name} has no model that supports physics units")
return self.__strengths

@property
Expand All @@ -365,7 +365,7 @@ def hardware(self) -> abstract.ReadWriteFloatScalar:
"""
self.check_peer()
if self.__hardwares is None:
raise PyAMLException(f"{str(self)} has no model that supports hardware units")
raise PyAMLException(f"{self.name} has no model that supports hardware units")
return self.__hardwares

def set_energy(self, energy: float):
Expand Down
12 changes: 12 additions & 0 deletions tests/diagnostics/bpm/test_bpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import pytest

from pyaml.accelerator import Accelerator
from pyaml.common.exception import PyAMLException
from pyaml.diagnostics.bpm.bpm import BPM


def test_simulator_bpm_tilt():
Expand Down Expand Up @@ -67,3 +69,13 @@ def test_simulator_bpm_position_with_bad_corrector_strength():
for bpm in [bpm1, bpm_simple, bpm3]:
assert bpm.positions.get()[0] != 0.0
assert bpm.positions.get()[1] != 0.0


def test_unattached_bpm_errors_name_bpm_without_formatting_it():
bpm = BPM(name="BPM1")

for accessor in ("positions", "offset", "tilt"):
with pytest.raises(PyAMLException, match=f"BPM1 has no attached {accessor}"):
getattr(bpm, accessor)

assert "BPM1" in repr(bpm)
16 changes: 16 additions & 0 deletions tests/magnet/test_missing_model_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import pytest

from pyaml import PyAMLException
from pyaml.magnet.hcorrector import HCorrector


def test_missing_model_errors_name_magnet_without_formatting_it():
magnet = HCorrector("CH1").attach(object(), strength=None, hardware=None)

with pytest.raises(PyAMLException, match="CH1 has no model that supports physics units"):
_ = magnet.strength

with pytest.raises(PyAMLException, match="CH1 has no model that supports hardware units"):
_ = magnet.hardware

assert "CH1" in repr(magnet)
Loading