diff --git a/.github/workflows/local_examples.yml b/.github/workflows/local_examples.yml new file mode 100644 index 0000000..d807fe2 --- /dev/null +++ b/.github/workflows/local_examples.yml @@ -0,0 +1,35 @@ +name: tests + +on: + push: + branches: + - "main" + pull_request: + +concurrency: + group: ${{ github.ref }}-${{ github.head_ref }}-local-examples + cancel-in-progress: true + +permissions: + contents: read # access to check out code and install dependencies + +jobs: + local-examples: + name: local examples + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + steps: + - uses: actions/checkout@v6 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + - name: Install + run: | + python -m pip install --upgrade pip + pip install ".[test]" + - name: Run local examples + run: | + python examples/fodo.py diff --git a/.github/workflows/tests.yml b/.github/workflows/unit_tests.yml similarity index 62% rename from .github/workflows/tests.yml rename to .github/workflows/unit_tests.yml index e4d8a66..5ab4934 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/unit_tests.yml @@ -1,4 +1,4 @@ -name: pals +name: tests on: push: @@ -7,29 +7,29 @@ on: pull_request: concurrency: - group: ${{ github.ref }}-${{ github.head_ref }}-pals-python + group: ${{ github.ref }}-${{ github.head_ref }}-unit-tests cancel-in-progress: true +permissions: + contents: read # access to check out code and install dependencies + jobs: - tests: - name: tests + unit-tests: + name: unit tests runs-on: ubuntu-latest strategy: matrix: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - name: Install run: | python -m pip install --upgrade pip pip install ".[test]" - - name: Test + - name: Run unit tests run: | pytest tests -v - - name: Examples - run: | - python examples/fodo.py diff --git a/.github/workflows/upstream_examples.yml b/.github/workflows/upstream_examples.yml new file mode 100644 index 0000000..6fb0a76 --- /dev/null +++ b/.github/workflows/upstream_examples.yml @@ -0,0 +1,45 @@ +name: tests + +on: + push: + branches: + - "main" + pull_request: + +concurrency: + group: ${{ github.ref }}-${{ github.head_ref }}-upstream-examples + cancel-in-progress: true + +permissions: + contents: read # access to check out code and install dependencies + +jobs: + upstream-examples: + name: upstream examples + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + steps: + - uses: actions/checkout@v6 + - name: Checkout upstream PALS repo + uses: actions/checkout@v6 + with: + repository: pals-project/pals + path: pals_temp + fetch-depth: 1 + sparse-checkout: | + examples/ + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + - name: Install + run: | + python -m pip install --upgrade pip + pip install ".[test]" + - name: Run upstream examples + run: | + for file in pals_temp/examples/*.pals.yaml; do + python tests/validate_upstream_examples.py --path "${file}" + done diff --git a/src/pals/kinds/mixin/all_element_mixin.py b/src/pals/kinds/mixin/all_element_mixin.py index 0c6be15..70ceb6e 100644 --- a/src/pals/kinds/mixin/all_element_mixin.py +++ b/src/pals/kinds/mixin/all_element_mixin.py @@ -61,7 +61,17 @@ def unpack_element_list_structure( f"but we got {item!r}" ) name, fields = list(item.items())[0] + # In addition to the existing shorthand `- element_name` + # (a plain string reference), also allow the alternative + # reference syntax `- use: element_name`. + # If the value is not a dict but the key is 'use', + # treat it as a reference to an existing element name + # and wrap it in a PlaceholderName so downstream code + # can resolve it. if not isinstance(fields, dict): + if name == "use" and isinstance(fields, str): + new_list.append(PlaceholderName(fields)) + continue raise TypeError( f"Value for element key {name!r} must be a dict (the element's properties), " f"but we got {fields!r}" diff --git a/tests/validate_upstream_examples.py b/tests/validate_upstream_examples.py new file mode 100644 index 0000000..aa1e40c --- /dev/null +++ b/tests/validate_upstream_examples.py @@ -0,0 +1,37 @@ +import argparse + +from pals import load +from pals.kinds import PlaceholderName +from pals.kinds.BeamLine import BeamLine +from pals.kinds.Drift import Drift +from pals.kinds.Lattice import Lattice +from pals.kinds.Quadrupole import Quadrupole + + +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 = load(example_file) + assert isinstance(lattice.facility[0], Drift) + assert lattice.facility[0].name == "drift1" + assert isinstance(lattice.facility[1], Quadrupole) + assert lattice.facility[1].name == "quad1" + assert isinstance(lattice.facility[2], BeamLine) + assert lattice.facility[2].name == "fodo_cell" + assert isinstance(lattice.facility[3], BeamLine) + assert lattice.facility[3].name == "fodo_channel" + assert isinstance(lattice.facility[4], Lattice) + assert lattice.facility[4].name == "fodo_lattice" + assert isinstance(lattice.facility[5], PlaceholderName) + + +if __name__ == "__main__": + main()