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
16 changes: 15 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ jobs:
- name: Test
run: |
pytest tests -v
- name: Examples
- name: Examples (internal)
run: |
python examples/fodo.py
- name: Examples (external)
run: |
# Copy examples directory from the main PALS repository
cd examples
git clone --no-checkout https://github.com/pals-project/pals.git pals_temp
Copy link
Member

@ax3l ax3l Jan 7, 2026

Choose a reason for hiding this comment

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

For stability (avoid triggering limits), we want to use the GH action checkout for all checkouts.
It supports sub-options for creating the clone in a specific folder. It also supports sparse checkouts and shallow fetch depths.
https://github.com/actions/checkout?tab=readme-ov-file#checkout-v6

cd pals_temp
git sparse-checkout init
git sparse-checkout set examples/
git checkout main
# Test all external examples
cd -
for file in pals_temp/examples/*.pals.yaml; do
python test_external_examples.py --path "${file}"
done
21 changes: 21 additions & 0 deletions examples/test_external_examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import argparse

from pals import Lattice


def main():
# Parse command-line arguments
parser = argparse.ArgumentParser()
parser.add_argument(
"--path",
required=True,
help="Path to the example file",
)
args = parser.parse_args()
example_file = args.path
# Parse and validate YAML data from file
Lattice.from_file(example_file)


if __name__ == "__main__":
main()
12 changes: 0 additions & 12 deletions src/pals/kinds/BeamLine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from .all_elements import get_all_elements_as_annotation
from .mixin import BaseElement
from ..functions import load_file_to_dict, store_dict_to_file


class BeamLine(BaseElement):
Expand All @@ -26,14 +25,3 @@ def model_dump(self, *args, **kwargs):
from pals.kinds.mixin.all_element_mixin import dump_element_list

return dump_element_list(self, "line", *args, **kwargs)

@staticmethod
def from_file(filename: str) -> "BeamLine":
"""Load a BeamLine from a text file"""
pals_dict = load_file_to_dict(filename)
return BeamLine(**pals_dict)

def to_file(self, filename: str):
"""Save a BeamLine to a text file"""
pals_dict = self.model_dump()
store_dict_to_file(filename, pals_dict)
39 changes: 39 additions & 0 deletions src/pals/kinds/Lattice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from pydantic import model_validator
from typing import List, Literal

from .all_elements import get_all_elements_as_annotation
from .mixin import BaseElement
from ..functions import load_file_to_dict, store_dict_to_file


class Lattice(BaseElement):
"""A line of elements and/or other lines"""

kind: Literal["Lattice"] = "Lattice"

branches: List[Annotated[Union[BeamLine], Field(discriminator="kind")]]

@model_validator(mode="before")
@classmethod
def unpack_json_structure(cls, data):
"""Deserialize the JSON/YAML/...-like dict for Lattice elements"""
from pals.kinds.mixin.all_element_mixin import unpack_element_list_structure

return unpack_element_list_structure(data, "line", "line")

def model_dump(self, *args, **kwargs):
"""Custom model dump for Lattice to handle element list formatting"""
from pals.kinds.mixin.all_element_mixin import dump_element_list

return dump_element_list(self, "line", *args, **kwargs)

@staticmethod
def from_file(filename: str) -> "Lattice":
"""Load a Lattice from a text file"""
pals_dict = load_file_to_dict(filename)
return Lattice(**pals_dict)

def to_file(self, filename: str):
"""Save a Lattice to a text file"""
pals_dict = self.model_dump()
store_dict_to_file(filename, pals_dict)
2 changes: 2 additions & 0 deletions src/pals/kinds/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .ACKicker import ACKicker # noqa: F401
from .BeamBeam import BeamBeam # noqa: F401
from .BeamLine import BeamLine # noqa: F401
from .Lattice import Lattice # noqa: F401
from .BeginningEle import BeginningEle # noqa: F401
from .Converter import Converter # noqa: F401
from .CrabCavity import CrabCavity # noqa: F401
Expand Down Expand Up @@ -39,3 +40,4 @@
# Rebuild pydantic models that depend on other classes
UnionEle.model_rebuild()
BeamLine.model_rebuild()
Lattice.model_rebuild()
1 change: 1 addition & 0 deletions src/pals/kinds/all_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
def get_all_element_types(extra_types: tuple = None):
"""Return a tuple of all element types that can be used in BeamLine or UnionEle."""
element_types = (
"Lattice", # Forward reference to handle circular import
"BeamLine", # Forward reference to handle circular import
"UnionEle", # Forward reference to handle circular import
ACKicker,
Expand Down
Loading