-
Notifications
You must be signed in to change notification settings - Fork 3
Fix NumPy Serialization #71
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import pytest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import pals | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -332,3 +334,75 @@ def test_comprehensive_lattice(): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Clean up temporary files | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| os.remove(yaml_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| os.remove(json_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _build_numpy_lattice(np): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Build a small lattice using numpy-typed scalar values throughout.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| quad = pals.Quadrupole( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name="q_np", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| length=np.float64(0.061), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MagneticMultipoleP=pals.MagneticMultipoleParameters( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Bn1=np.float64(-26.0), Bs1=np.float32(0.5), Kn0=np.int64(-1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| oct_ = pals.Octupole( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name="o_np", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| length=np.float64(0.25), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ElectricMultipoleP=pals.ElectricMultipoleParameters( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| En3=np.float64(0.75), Es3=np.float32(0.125) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return pals.BeamLine(name="line_np", line=[quad, oct_]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_yaml_roundtrip_with_numpy(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Regression test for issue #67: writing YAML with numpy-typed values | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| must not produce !!python/object tags, and round-tripping must yield | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Python-native floats with the correct numeric values.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| np = pytest.importorskip("numpy") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| line = _build_numpy_lattice(np) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml_file = "numpy_roundtrip.pals.yaml" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| line.to_file(yaml_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(yaml_file, "r") as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| text = f.read() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # The bug symptom: YAML contains opaque numpy object tags. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert "!!python/object" not in text, ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| f"YAML output still contains unsafe numpy object tags:\n{text}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert "numpy" not in text, f"YAML output still references numpy:\n{text}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loaded = pals.BeamLine.from_file(yaml_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loaded_quad = loaded.line[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert loaded_quad.MagneticMultipoleP.Bn1 == -26.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert type(loaded_quad.MagneticMultipoleP.Bn1) is float | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert loaded_quad.MagneticMultipoleP.Bs1 == 0.5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert loaded_quad.MagneticMultipoleP.Kn0 == -1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loaded_oct = loaded.line[1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert loaded_oct.ElectricMultipoleP.En3 == 0.75 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert type(loaded_oct.ElectricMultipoleP.En3) is float | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| finally: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if os.path.exists(yaml_file): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| os.remove(yaml_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_json_roundtrip_with_numpy(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """JSON path also needs to handle numpy values cleanly (defense-in-depth).""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| np = pytest.importorskip("numpy") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| line = _build_numpy_lattice(np) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| json_file = "numpy_roundtrip.pals.json" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| line.to_file(json_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loaded = pals.BeamLine.from_file(json_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loaded_quad = loaded.line[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert loaded_quad.MagneticMultipoleP.Bn1 == -26.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert type(loaded_quad.MagneticMultipoleP.Bn1) is float | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loaded_oct = loaded.line[1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert loaded_oct.ElectricMultipoleP.En3 == 0.75 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| finally: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if os.path.exists(json_file): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| os.remove(json_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+392
to
+408
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could use pytest's
Suggested change
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For convenience, the diff without whitespace would be: -def test_json_roundtrip_with_numpy():
+def test_json_roundtrip_with_numpy(tmp_path):
"""JSON path also needs to handle numpy values cleanly (defense-in-depth)."""
np = pytest.importorskip("numpy")
line = _build_numpy_lattice(np)
- json_file = "numpy_roundtrip.pals.json"
+ json_file = str(tmp_path / "numpy_roundtrip.pals.json")
line.to_file(json_file)
- try:
+
loaded = pals.BeamLine.from_file(json_file)
loaded_quad = loaded.line[0]
assert loaded_quad.MagneticMultipoleP.Bn1 == -26.0
assert type(loaded_quad.MagneticMultipoleP.Bn1) is float
loaded_oct = loaded.line[1]
assert loaded_oct.ElectricMultipoleP.En3 == 0.75
- finally:
- if os.path.exists(json_file):
- os.remove(json_file) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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 use pytest's
tmp_pathfixture to avoid polluting and cleaning the root directory (notry/finally, noos.remove, etc.):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.
For convenience, the diff without whitespace would be: