Skip to content
Merged
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ jobs:
- name: Gate (tools/test.sh, release)
run: tools/test.sh

lint:
name: Lint (shared SwiftLint and SwiftFormat config)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: SwiftLint
run: docker run --rm -v "$PWD:/work" -w /work --entrypoint swiftlint ghcr.io/realm/swiftlint:0.65.1 lint --strict --quiet
- name: SwiftFormat
run: docker run --rm -v "$PWD:/work" -w /work --entrypoint swiftformat ghcr.io/nicklockwood/swiftformat:0.64.4 --lint .

private-refs:
name: No private references
runs-on: ubuntu-latest
Expand Down
45 changes: 45 additions & 0 deletions .github/workflows/periphery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Weekly unused-code scan (Periphery). A copy of the suite's template; edit it there.
# Builds the package and its tests, scans with --retain-public (a kit's public API is used by the apps), and keeps one
# open issue, "Periphery weekly scan", up to date with the findings. Findings are for triage; nothing is deleted here.
name: Periphery

on:
schedule:
- cron: "17 3 * * 0"
workflow_dispatch:

permissions:
contents: read
issues: write

jobs:
scan:
runs-on: macos-26
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Install Periphery
run: brew install periphery && periphery version
- name: Build with the index store
run: swift build --build-system native --build-tests
- name: Scan
run: |
periphery scan --retain-public --skip-build --index-store-path .build/debug/index/store \
--format csv --relative-results > periphery.csv
echo "count=$(( $(wc -l < periphery.csv) - 1 ))" >> "$GITHUB_ENV"
- name: Update the issue
env:
GH_TOKEN: ${{ github.token }}
run: |
title="Periphery weekly scan"
echo "Periphery $(periphery version), commit ${GITHUB_SHA::7}, $(date -u +%Y-%m-%d): **${count} findings** (run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})." > body.md
printf '\n| Kind | Name | Location | Hint |\n|---|---|---|---|\n' >> body.md
python3 - >> body.md <<'PY'
import csv
for r in list(csv.DictReader(open('periphery.csv')))[:100]:
print(f"| {r['Kind']} | `{r['Name']}` | {r['Location']} | {r['Hints']} |")
PY
[ "$count" -le 100 ] || echo "| … | $((count - 100)) more in the run's log | | |" >> body.md
cat periphery.csv
n=$(gh issue list --state open --search "in:title \"$title\"" --json number,title -q ".[] | select(.title == \"$title\") | .number" | head -1)
if [ -n "$n" ]; then gh issue edit "$n" --body-file body.md; else gh issue create --title "$title" --body-file body.md; fi
5 changes: 5 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# The suite's one SwiftFormat config. tools/lint/sync.sh copies it to every Swift repo as .swiftformat; edit it here only.
# CI runs `swiftformat --lint .`: whitespace and a few unambiguous fixes, nothing that reflows code.
--swiftversion 6.2
--exclude .build,build,References,DerivedData
--rules trailingSpace,linebreakAtEndOfFile,consecutiveBlankLines,duplicateImports,semicolons,spaceAroundParens,emptyBraces,todos
33 changes: 33 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# The suite's one SwiftLint config. tools/lint/sync.sh copies it to every Swift repo as .swiftlint.yml; edit it here only.
# Rules that catch a mistake or keep files tidy, all fixable without touching a number or a name. Not enabled, on purpose:
# identifier_name and type_name (the ported Python names: nx, q, E0), line_length (the house style runs to about 150 columns),
# force_unwrapping and force_try (tests and fixtures), identical_operands (`x != x` is a NaN test in numeric code),
# orphaned_doc_comment (a `// delete at` note between a doc comment and its declaration is the house idiom).
excluded:
- .build
- build
- References
- DerivedData
only_rules:
- duplicate_imports
- duplicate_enum_cases
- duplicated_key_in_dictionary_literal
- duplicate_conditions
- unused_optional_binding
- unused_setter_value
- discarded_notification_center_observer
- unneeded_override
- control_statement
- void_return
- trailing_whitespace
- trailing_newline
- leading_whitespace
- vertical_whitespace
- comment_spacing
- return_arrow_whitespace
- legacy_constructor
- legacy_cggeometry_functions
- legacy_nsgeometry_functions
- superfluous_disable_command
- blanket_disable_command
- invalid_swiftlint_command
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ public nonisolated enum ProposerError: Error, Equatable {
case cancelled
}


public nonisolated struct ElementProposer: Sendable {
package var currie: Currie
/// The elements tested; nil is `defaultPool`.
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpectroEELS/EELSComposition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public enum EELSQuantification {
var columns: [Int] = []
if let dup = symbols.enumerated().first(where: { i, s in symbols[..<i].contains(s) })?.element { throw EELSModelError.symbolNotFitted(dup + " (listed twice)") }
for s in symbols {
guard let g = result.edges.firstIndex(where: { $0.element == s }), let _ = atomicMasses[s] else { throw EELSModelError.symbolNotFitted(s) }
guard let g = result.edges.firstIndex(where: { $0.element == s }), atomicMasses[s] != nil else { throw EELSModelError.symbolNotFitted(s) }
columns.append(g)
}
let masses = symbols.map { atomicMasses[$0]! }
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpectroEELS/EdgeCrossSection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// computes it: the effective collection angle (`exspy/utils/eels/effective_angle.py:23-80`, Egerton 2nd ed. p. 420),
// the q integration (`exspy/_misc/eels/base_gos.py`, `get_qaxis_and_gos` and `integrateq`), the interpolating
// spline between tabulated energies and the power law beyond them (`components/_eels_cl_edge.py:436-494`).
//
//
//
// Precision as exSpy runs on NumPy 2.5.4: the GOS arrays are float32 and, by NEP 50, a Python float meeting a float32
// scalar or array is cast to float32, so the q limits, the GOS interpolated to q_max, the prefactor and the
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpectroEELS/GOSTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// GOSTable.swift
// Role: The generalised oscillator strength of one K shell, as exSpy 7185a4d1 reads it from the GOSH database
// (`exspy/_misc/eels/gosh_gos.py`, `read_gos_data`; `base_gos.py`, `TabulatedGOS`), and the edges SpectroKit ships.
//
//
//
// The tables are the dft GOS of Segger, Guzzinati and Kohl (GOSH 1.5.0, DOI 10.5281/zenodo.7645765, CC-BY-4.0; md5 of the
// file exSpy fetches 7fee8891c147a4f769668403b54c529b), the groups C/K1, N/K1 and O/K1, extracted by
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpectroEELS/PowerLawBackground.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Role: The pre-edge background A E^-r by HyperSpy 2.4.0's two-area estimate (`_components/power_law.py:100-187`,
// `PowerLaw.estimate_parameters`), evaluated as `remove_background(fast=True)` evaluates it on a binned axis
// (`_signals/signal1d.py:1102-1152`; `models/model1d.py:375-390`: the component's value times the channel width).
//
//
//
// Departure from HyperSpy: where a window sum is not positive or A, r come out non-finite,
// HyperSpy's `nan_to_num` (or, on a zero sum, the whole image's estimate failing) is replaced by a nil pixel with its
Expand Down
1 change: 0 additions & 1 deletion Tests/SpectroEELSTests/EdgeWindowsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ struct EdgeWindowsTests {
#expect((1.5 ... 4).contains(w.exponent(pixel: 0, edge: 0)!)) // between the tail (3) and the shallower part (1)
}


/// The real-file case: the N K default background window (319 to 396 eV) lies in the tail of C K, which dominates a weak background.
@Test func testStrippingRecoversNKInsideTheCTail() throws {
let (core, mic, ratio) = try planted(curved: true, backgroundScale: 0.02, ratio: [100, 1, 2])
Expand Down
1 change: 0 additions & 1 deletion Tests/SpectroKitParityTests/EDSQuantPinsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ struct EDSQuantPinsTests {
#expect(compared >= 20)
}


/// Where eXSpy's signed maximum stops early (the criterion_split cases: 3 and 4 elements), the default `.absolute` rule runs on
/// and ends nearer the fixed point; the difference is bounded by the stopping error. Without these two cases the comparison above
/// would hold trivially (every two-element set, and every other set here, stops on the same iteration under both rules).
Expand Down
Loading