ad-hoc-diffractometer 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ad_hoc_diffractometer-0.3.1/.copyright.txt +2 -0
- ad_hoc_diffractometer-0.3.1/.github/dependabot.yml +11 -0
- ad_hoc_diffractometer-0.3.1/.github/workflows/docs.yml +225 -0
- ad_hoc_diffractometer-0.3.1/.github/workflows/docs_backfill.yml +191 -0
- ad_hoc_diffractometer-0.3.1/.github/workflows/pypi.yml +47 -0
- ad_hoc_diffractometer-0.3.1/.github/workflows/tests.yml +44 -0
- ad_hoc_diffractometer-0.3.1/.gitignore +22 -0
- ad_hoc_diffractometer-0.3.1/.pre-commit-config.yaml +40 -0
- ad_hoc_diffractometer-0.3.1/AGENTS.md +347 -0
- ad_hoc_diffractometer-0.3.1/CHANGES.md +177 -0
- ad_hoc_diffractometer-0.3.1/LICENSE +95 -0
- ad_hoc_diffractometer-0.3.1/PKG-INFO +36 -0
- ad_hoc_diffractometer-0.3.1/README.md +68 -0
- ad_hoc_diffractometer-0.3.1/docs/Makefile +14 -0
- ad_hoc_diffractometer-0.3.1/docs/make.bat +30 -0
- ad_hoc_diffractometer-0.3.1/docs/source/_static/switcher.json +11 -0
- ad_hoc_diffractometer-0.3.1/docs/source/api.rst +12 -0
- ad_hoc_diffractometer-0.3.1/docs/source/changes.md +4 -0
- ad_hoc_diffractometer-0.3.1/docs/source/conf.py +126 -0
- ad_hoc_diffractometer-0.3.1/docs/source/direct-lattice.md +92 -0
- ad_hoc_diffractometer-0.3.1/docs/source/fourcv_alignment_howto.ipynb +840 -0
- ad_hoc_diffractometer-0.3.1/docs/source/index.rst +36 -0
- ad_hoc_diffractometer-0.3.1/docs/source/install.md +42 -0
- ad_hoc_diffractometer-0.3.1/docs/source/problem1.md +78 -0
- ad_hoc_diffractometer-0.3.1/docs/source/problem1_solution.pdf +0 -0
- ad_hoc_diffractometer-0.3.1/docs/source/problem1_solution.tex +250 -0
- ad_hoc_diffractometer-0.3.1/docs/source/problem2.md +155 -0
- ad_hoc_diffractometer-0.3.1/docs/source/problem3.md +8 -0
- ad_hoc_diffractometer-0.3.1/docs/source/roadmap.md +618 -0
- ad_hoc_diffractometer-0.3.1/pyproject.toml +116 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/__init__.py +202 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/_version.py +24 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/axes.py +265 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/constants.py +25 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/display.py +164 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/engines.py +508 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/factories.py +951 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/forward.py +617 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/geometry.py +2114 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/lattice.py +816 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/mode.py +390 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/orientation.py +815 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/radiation.py +361 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/refinement.py +973 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/reflection.py +432 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/rotation.py +70 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/sample.py +280 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/scan.py +1035 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/stage.py +164 -0
- ad_hoc_diffractometer-0.3.1/src/ad_hoc_diffractometer/surface.py +433 -0
- ad_hoc_diffractometer-0.3.1/tests/__init__.py +0 -0
- ad_hoc_diffractometer-0.3.1/tests/conftest.py +34 -0
- ad_hoc_diffractometer-0.3.1/tests/helpers.py +51 -0
- ad_hoc_diffractometer-0.3.1/tests/test_axes.py +269 -0
- ad_hoc_diffractometer-0.3.1/tests/test_display.py +162 -0
- ad_hoc_diffractometer-0.3.1/tests/test_engines.py +441 -0
- ad_hoc_diffractometer-0.3.1/tests/test_factories.py +1008 -0
- ad_hoc_diffractometer-0.3.1/tests/test_forward.py +590 -0
- ad_hoc_diffractometer-0.3.1/tests/test_geometry.py +2002 -0
- ad_hoc_diffractometer-0.3.1/tests/test_lattice.py +978 -0
- ad_hoc_diffractometer-0.3.1/tests/test_mode.py +747 -0
- ad_hoc_diffractometer-0.3.1/tests/test_orientation.py +1378 -0
- ad_hoc_diffractometer-0.3.1/tests/test_radiation.py +645 -0
- ad_hoc_diffractometer-0.3.1/tests/test_refinement.py +734 -0
- ad_hoc_diffractometer-0.3.1/tests/test_reflection.py +748 -0
- ad_hoc_diffractometer-0.3.1/tests/test_rotation.py +100 -0
- ad_hoc_diffractometer-0.3.1/tests/test_sample.py +536 -0
- ad_hoc_diffractometer-0.3.1/tests/test_scan.py +981 -0
- ad_hoc_diffractometer-0.3.1/tests/test_stage.py +310 -0
- ad_hoc_diffractometer-0.3.1/tests/test_surface.py +638 -0
- ad_hoc_diffractometer-0.3.1/threading_diagnostics.md +473 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Set update schedule for GitHub Actions
|
|
2
|
+
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
|
|
3
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
4
|
+
|
|
5
|
+
version: 2
|
|
6
|
+
updates:
|
|
7
|
+
- package-ecosystem: "github-actions"
|
|
8
|
+
directory: "/"
|
|
9
|
+
schedule:
|
|
10
|
+
# Check for updates to GitHub Actions every week
|
|
11
|
+
interval: "weekly"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
name: Publish Sphinx Docs to GitHub Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
tags:
|
|
8
|
+
- '*'
|
|
9
|
+
pull_request:
|
|
10
|
+
branches:
|
|
11
|
+
- main
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
inputs:
|
|
14
|
+
deploy:
|
|
15
|
+
description: 'Deploy documentation'
|
|
16
|
+
type: boolean
|
|
17
|
+
required: true
|
|
18
|
+
default: false
|
|
19
|
+
|
|
20
|
+
concurrency:
|
|
21
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
22
|
+
cancel-in-progress: true
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
contents: write
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
|
|
29
|
+
docs:
|
|
30
|
+
name: Build and publish documentation
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
|
|
33
|
+
steps:
|
|
34
|
+
|
|
35
|
+
- name: Checkout
|
|
36
|
+
uses: actions/checkout@v6
|
|
37
|
+
with:
|
|
38
|
+
fetch-depth: 0 # full history so hatch-vcs can read git tags
|
|
39
|
+
|
|
40
|
+
- name: Set up Python
|
|
41
|
+
uses: actions/setup-python@v6
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.12"
|
|
44
|
+
cache: pip
|
|
45
|
+
|
|
46
|
+
- name: Install pandoc
|
|
47
|
+
run: |
|
|
48
|
+
sudo apt-get update
|
|
49
|
+
sudo apt-get install -y pandoc
|
|
50
|
+
|
|
51
|
+
- name: Install package with doc dependencies
|
|
52
|
+
run: pip install -e .[doc]
|
|
53
|
+
|
|
54
|
+
- name: Determine DOC_VERSION
|
|
55
|
+
run: |
|
|
56
|
+
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
57
|
+
VERSION="${GITHUB_REF#refs/tags/}"
|
|
58
|
+
else
|
|
59
|
+
VERSION="latest"
|
|
60
|
+
fi
|
|
61
|
+
echo "DOC_VERSION=${VERSION}" >> "${GITHUB_ENV}"
|
|
62
|
+
echo "Publishing docs as: ${VERSION}"
|
|
63
|
+
|
|
64
|
+
- name: Build Sphinx documentation
|
|
65
|
+
# Note: -W (warnings-as-errors) is intentionally omitted here.
|
|
66
|
+
# Pre-existing docstring formatting issues produce AutoAPI warnings
|
|
67
|
+
# that are tracked separately and will be fixed in Phase 2 content work.
|
|
68
|
+
run: |
|
|
69
|
+
python3 -m sphinx -b html docs/source docs/build/html
|
|
70
|
+
|
|
71
|
+
- name: Upload docs as workflow artifact
|
|
72
|
+
uses: actions/upload-artifact@v7
|
|
73
|
+
with:
|
|
74
|
+
name: docs-${{ env.DOC_VERSION }}
|
|
75
|
+
path: docs/build/html
|
|
76
|
+
|
|
77
|
+
- name: Deploy to gh-pages — latest/ (main push)
|
|
78
|
+
uses: peaceiris/actions-gh-pages@v4
|
|
79
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
80
|
+
with:
|
|
81
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
82
|
+
publish_branch: gh-pages
|
|
83
|
+
publish_dir: docs/build/html
|
|
84
|
+
destination_dir: latest
|
|
85
|
+
keep_files: true
|
|
86
|
+
|
|
87
|
+
- name: Deploy to gh-pages — <version>/ (tag push)
|
|
88
|
+
uses: peaceiris/actions-gh-pages@v4
|
|
89
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
90
|
+
with:
|
|
91
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
92
|
+
publish_branch: gh-pages
|
|
93
|
+
publish_dir: docs/build/html
|
|
94
|
+
destination_dir: ${{ env.DOC_VERSION }}
|
|
95
|
+
keep_files: true
|
|
96
|
+
|
|
97
|
+
- name: Update switcher.json on tag push
|
|
98
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
99
|
+
run: |
|
|
100
|
+
set -euo pipefail
|
|
101
|
+
VERSION="${DOC_VERSION}"
|
|
102
|
+
|
|
103
|
+
# Clone gh-pages to update switcher.json
|
|
104
|
+
git clone --branch gh-pages --depth 1 \
|
|
105
|
+
"https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" \
|
|
106
|
+
gh-pages-clone
|
|
107
|
+
|
|
108
|
+
SWITCHER="gh-pages-clone/latest/_static/switcher.json"
|
|
109
|
+
|
|
110
|
+
# If switcher.json doesn't exist yet, bootstrap from source
|
|
111
|
+
if [ ! -f "${SWITCHER}" ]; then
|
|
112
|
+
mkdir -p "$(dirname ${SWITCHER})"
|
|
113
|
+
cp docs/source/_static/switcher.json "${SWITCHER}"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Update switcher.json.
|
|
117
|
+
# Pre-releases (rcN, aN, bN) appear in the switcher but do not steal
|
|
118
|
+
# "preferred" from the current stable release.
|
|
119
|
+
# Stable releases also prune all pre-release entries for the same
|
|
120
|
+
# base version (e.g. finalising 0.4.1 removes 0.4.1rc1, 0.4.1a1, …).
|
|
121
|
+
python3 - <<'PYEOF'
|
|
122
|
+
import json, os, re
|
|
123
|
+
|
|
124
|
+
version = os.environ["VERSION"]
|
|
125
|
+
switcher_path = os.environ["SWITCHER"]
|
|
126
|
+
base_url = "https://prjemian.github.io/ad_hoc_diffractometer"
|
|
127
|
+
|
|
128
|
+
is_prerelease = bool(re.search(r'(a|b|rc)\d+$', version))
|
|
129
|
+
|
|
130
|
+
with open(switcher_path) as f:
|
|
131
|
+
entries = json.load(f)
|
|
132
|
+
|
|
133
|
+
versions = [e["version"] for e in entries]
|
|
134
|
+
insert_pos = next(
|
|
135
|
+
(i + 1 for i, e in enumerate(entries) if e.get("version") == "latest"),
|
|
136
|
+
1,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
if not is_prerelease:
|
|
140
|
+
# Remove all pre-release entries for this base version.
|
|
141
|
+
prerelease_pat = re.compile(r'^' + re.escape(version) + r'(a|b|rc)\d+$')
|
|
142
|
+
pruned = [e["version"] for e in entries if prerelease_pat.match(e["version"])]
|
|
143
|
+
entries = [e for e in entries if not prerelease_pat.match(e["version"])]
|
|
144
|
+
for v in pruned:
|
|
145
|
+
print(f"Removed pre-release {v} from switcher.json")
|
|
146
|
+
# Recalculate insert position after pruning.
|
|
147
|
+
insert_pos = next(
|
|
148
|
+
(i + 1 for i, e in enumerate(entries) if e.get("version") == "latest"),
|
|
149
|
+
1,
|
|
150
|
+
)
|
|
151
|
+
versions = [e["version"] for e in entries]
|
|
152
|
+
# Clear preferred everywhere, then mark this stable version.
|
|
153
|
+
for e in entries:
|
|
154
|
+
e.pop("preferred", None)
|
|
155
|
+
if version in versions:
|
|
156
|
+
for e in entries:
|
|
157
|
+
if e["version"] == version:
|
|
158
|
+
e["preferred"] = True
|
|
159
|
+
print(f"{version} already present; marked preferred")
|
|
160
|
+
else:
|
|
161
|
+
new_entry = {"version": version, "url": f"{base_url}/{version}/", "preferred": True}
|
|
162
|
+
entries.insert(insert_pos, new_entry)
|
|
163
|
+
print(f"Added {version} to switcher.json and marked preferred")
|
|
164
|
+
else:
|
|
165
|
+
# Pre-release: add without touching preferred.
|
|
166
|
+
if version in versions:
|
|
167
|
+
print(f"{version} already present (pre-release; preferred unchanged)")
|
|
168
|
+
else:
|
|
169
|
+
new_entry = {"version": version, "url": f"{base_url}/{version}/"}
|
|
170
|
+
entries.insert(insert_pos, new_entry)
|
|
171
|
+
print(f"Added pre-release {version} to switcher.json (preferred unchanged)")
|
|
172
|
+
|
|
173
|
+
with open(switcher_path, "w") as f:
|
|
174
|
+
json.dump(entries, f, indent=4)
|
|
175
|
+
PYEOF
|
|
176
|
+
env:
|
|
177
|
+
SWITCHER: gh-pages-clone/latest/_static/switcher.json
|
|
178
|
+
VERSION: ${{ env.DOC_VERSION }}
|
|
179
|
+
|
|
180
|
+
- name: Remove pre-release doc directories from gh-pages on stable tag
|
|
181
|
+
if: >
|
|
182
|
+
github.event_name == 'push' &&
|
|
183
|
+
startsWith(github.ref, 'refs/tags/') &&
|
|
184
|
+
!contains(env.DOC_VERSION, 'a') &&
|
|
185
|
+
!contains(env.DOC_VERSION, 'b') &&
|
|
186
|
+
!contains(env.DOC_VERSION, 'rc')
|
|
187
|
+
run: |
|
|
188
|
+
set -euo pipefail
|
|
189
|
+
VERSION="${DOC_VERSION}"
|
|
190
|
+
|
|
191
|
+
# Delete gh-pages/<base>rcN, <base>aN, <base>bN directories if present.
|
|
192
|
+
PRUNED=()
|
|
193
|
+
for dir in gh-pages-clone/${VERSION}{a,b,rc}*/; do
|
|
194
|
+
[ -d "${dir}" ] || continue
|
|
195
|
+
rm -rf "${dir}"
|
|
196
|
+
PRUNED+=("${dir}")
|
|
197
|
+
echo "Removed directory: ${dir}"
|
|
198
|
+
done
|
|
199
|
+
|
|
200
|
+
if [[ ${#PRUNED[@]} -eq 0 ]]; then
|
|
201
|
+
echo "No pre-release directories found for ${VERSION}."
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
- name: Commit switcher.json and pruned directories to gh-pages
|
|
205
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
206
|
+
run: |
|
|
207
|
+
cd gh-pages-clone
|
|
208
|
+
git config user.name "github-actions[bot]"
|
|
209
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
210
|
+
git add -A
|
|
211
|
+
git diff --cached --quiet || git commit -m "ci: release ${DOC_VERSION}: update switcher.json, prune pre-release docs"
|
|
212
|
+
# Pull with rebase before pushing to avoid "fetch first" rejection
|
|
213
|
+
# when the earlier gh-pages deploy step has already pushed to the branch.
|
|
214
|
+
git pull --rebase origin gh-pages
|
|
215
|
+
git push
|
|
216
|
+
|
|
217
|
+
- name: Deploy on manual trigger
|
|
218
|
+
uses: peaceiris/actions-gh-pages@v4
|
|
219
|
+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.deploy == 'true'
|
|
220
|
+
with:
|
|
221
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
222
|
+
publish_branch: gh-pages
|
|
223
|
+
publish_dir: docs/build/html
|
|
224
|
+
destination_dir: latest
|
|
225
|
+
keep_files: true
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
name: Backfill Docs for a Tagged Version
|
|
2
|
+
|
|
3
|
+
# Use this workflow to publish docs for a tag that was released before
|
|
4
|
+
# versioned docs were introduced. Run manually from the Actions tab.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# 1. Go to Actions -> "Backfill Docs for a Tagged Version"
|
|
8
|
+
# 2. Click "Run workflow"
|
|
9
|
+
# 3. Enter the tag (e.g. "v0.2.0") in the input field
|
|
10
|
+
# 4. Click "Run workflow"
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
inputs:
|
|
15
|
+
tag:
|
|
16
|
+
description: 'Tag to build and publish (e.g. v0.2.0)'
|
|
17
|
+
required: true
|
|
18
|
+
type: string
|
|
19
|
+
|
|
20
|
+
permissions:
|
|
21
|
+
contents: write
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
|
|
25
|
+
backfill:
|
|
26
|
+
name: Backfill docs for tag ${{ github.event.inputs.tag }}
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
|
|
29
|
+
steps:
|
|
30
|
+
|
|
31
|
+
- name: Deploy Information
|
|
32
|
+
run: |
|
|
33
|
+
echo "Building and publishing docs for tag: ${{ github.event.inputs.tag }}"
|
|
34
|
+
|
|
35
|
+
- name: Make Temporary Directory
|
|
36
|
+
run: |
|
|
37
|
+
echo "TMP_DIR=$(mktemp -d)" >> "${GITHUB_ENV}"
|
|
38
|
+
echo "DOC_VERSION=${{ github.event.inputs.tag }}" >> "${GITHUB_ENV}"
|
|
39
|
+
|
|
40
|
+
- name: Install pandoc
|
|
41
|
+
run: |
|
|
42
|
+
set -vxeuo pipefail
|
|
43
|
+
sudo apt-get update && sudo apt-get -y install pandoc
|
|
44
|
+
|
|
45
|
+
- name: Checkout tag
|
|
46
|
+
uses: actions/checkout@v6
|
|
47
|
+
with:
|
|
48
|
+
ref: ${{ github.event.inputs.tag }}
|
|
49
|
+
fetch-depth: 0
|
|
50
|
+
|
|
51
|
+
- name: Set up Python
|
|
52
|
+
uses: actions/setup-python@v6
|
|
53
|
+
with:
|
|
54
|
+
python-version: "3.12"
|
|
55
|
+
cache: pip
|
|
56
|
+
|
|
57
|
+
- name: Install package and doc requirements
|
|
58
|
+
run: pip install -e .[doc]
|
|
59
|
+
|
|
60
|
+
- name: Build docs
|
|
61
|
+
run: |
|
|
62
|
+
HTML_DIR="${TMP_DIR}/build/${DOC_VERSION}"
|
|
63
|
+
echo "HTML_DIR=${HTML_DIR}" >> "${GITHUB_ENV}"
|
|
64
|
+
python3 -m sphinx -b html docs/source "${HTML_DIR}"
|
|
65
|
+
|
|
66
|
+
- name: Upload artifact
|
|
67
|
+
uses: actions/upload-artifact@v7
|
|
68
|
+
with:
|
|
69
|
+
name: docs-${{ env.DOC_VERSION }}
|
|
70
|
+
path: ${{ env.HTML_DIR }}
|
|
71
|
+
|
|
72
|
+
- name: Deploy to gh-pages/<version>/
|
|
73
|
+
uses: peaceiris/actions-gh-pages@v4
|
|
74
|
+
with:
|
|
75
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
76
|
+
publish_branch: gh-pages
|
|
77
|
+
publish_dir: ${{ env.HTML_DIR }}
|
|
78
|
+
destination_dir: ${{ env.DOC_VERSION }}
|
|
79
|
+
keep_files: true
|
|
80
|
+
|
|
81
|
+
- name: Update switcher.json on gh-pages
|
|
82
|
+
run: |
|
|
83
|
+
set -euo pipefail
|
|
84
|
+
VERSION="${DOC_VERSION}"
|
|
85
|
+
|
|
86
|
+
git clone --branch gh-pages --depth 1 \
|
|
87
|
+
"https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" \
|
|
88
|
+
gh-pages-clone
|
|
89
|
+
|
|
90
|
+
SWITCHER="gh-pages-clone/latest/_static/switcher.json"
|
|
91
|
+
|
|
92
|
+
if [ ! -f "${SWITCHER}" ]; then
|
|
93
|
+
echo "switcher.json not found at ${SWITCHER} — skipping update"
|
|
94
|
+
exit 0
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Update switcher.json.
|
|
98
|
+
# Pre-releases (rcN, aN, bN) appear in the switcher but do not steal
|
|
99
|
+
# "preferred" from the current stable release.
|
|
100
|
+
# Stable releases also prune all pre-release entries for the same
|
|
101
|
+
# base version (e.g. finalising 0.4.1 removes 0.4.1rc1, 0.4.1a1, …).
|
|
102
|
+
python3 - <<'PYEOF'
|
|
103
|
+
import json, os, re
|
|
104
|
+
|
|
105
|
+
version = os.environ["VERSION"]
|
|
106
|
+
switcher_path = os.environ["SWITCHER"]
|
|
107
|
+
base_url = "https://prjemian.github.io/ad_hoc_diffractometer"
|
|
108
|
+
|
|
109
|
+
is_prerelease = bool(re.search(r'(a|b|rc)\d+$', version))
|
|
110
|
+
|
|
111
|
+
with open(switcher_path) as f:
|
|
112
|
+
entries = json.load(f)
|
|
113
|
+
|
|
114
|
+
versions = [e["version"] for e in entries]
|
|
115
|
+
insert_pos = next(
|
|
116
|
+
(i + 1 for i, e in enumerate(entries) if e.get("version") == "latest"),
|
|
117
|
+
1,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if not is_prerelease:
|
|
121
|
+
# Remove all pre-release entries for this base version.
|
|
122
|
+
prerelease_pat = re.compile(r'^' + re.escape(version) + r'(a|b|rc)\d+$')
|
|
123
|
+
pruned = [e["version"] for e in entries if prerelease_pat.match(e["version"])]
|
|
124
|
+
entries = [e for e in entries if not prerelease_pat.match(e["version"])]
|
|
125
|
+
for v in pruned:
|
|
126
|
+
print(f"Removed pre-release {v} from switcher.json")
|
|
127
|
+
# Recalculate insert position after pruning.
|
|
128
|
+
insert_pos = next(
|
|
129
|
+
(i + 1 for i, e in enumerate(entries) if e.get("version") == "latest"),
|
|
130
|
+
1,
|
|
131
|
+
)
|
|
132
|
+
versions = [e["version"] for e in entries]
|
|
133
|
+
# Clear preferred everywhere, then mark this stable version.
|
|
134
|
+
for e in entries:
|
|
135
|
+
e.pop("preferred", None)
|
|
136
|
+
if version in versions:
|
|
137
|
+
for e in entries:
|
|
138
|
+
if e["version"] == version:
|
|
139
|
+
e["preferred"] = True
|
|
140
|
+
print(f"{version} already present; marked preferred")
|
|
141
|
+
else:
|
|
142
|
+
new_entry = {"version": version, "url": f"{base_url}/{version}/", "preferred": True}
|
|
143
|
+
entries.insert(insert_pos, new_entry)
|
|
144
|
+
print(f"Added {version} and marked preferred")
|
|
145
|
+
else:
|
|
146
|
+
# Pre-release: add without touching preferred.
|
|
147
|
+
if version in versions:
|
|
148
|
+
print(f"{version} already present (pre-release; preferred unchanged)")
|
|
149
|
+
else:
|
|
150
|
+
new_entry = {"version": version, "url": f"{base_url}/{version}/"}
|
|
151
|
+
entries.insert(insert_pos, new_entry)
|
|
152
|
+
print(f"Added pre-release {version} (preferred unchanged)")
|
|
153
|
+
|
|
154
|
+
with open(switcher_path, "w") as f:
|
|
155
|
+
json.dump(entries, f, indent=4)
|
|
156
|
+
PYEOF
|
|
157
|
+
env:
|
|
158
|
+
SWITCHER: gh-pages-clone/latest/_static/switcher.json
|
|
159
|
+
VERSION: ${{ env.DOC_VERSION }}
|
|
160
|
+
|
|
161
|
+
- name: Remove pre-release doc directories from gh-pages on stable tag
|
|
162
|
+
if: >
|
|
163
|
+
!contains(env.DOC_VERSION, 'a') &&
|
|
164
|
+
!contains(env.DOC_VERSION, 'b') &&
|
|
165
|
+
!contains(env.DOC_VERSION, 'rc')
|
|
166
|
+
run: |
|
|
167
|
+
set -euo pipefail
|
|
168
|
+
VERSION="${DOC_VERSION}"
|
|
169
|
+
|
|
170
|
+
# Delete gh-pages/<base>rcN, <base>aN, <base>bN directories if present.
|
|
171
|
+
PRUNED=()
|
|
172
|
+
for dir in gh-pages-clone/${VERSION}{a,b,rc}*/; do
|
|
173
|
+
[ -d "${dir}" ] || continue
|
|
174
|
+
rm -rf "${dir}"
|
|
175
|
+
PRUNED+=("${dir}")
|
|
176
|
+
echo "Removed directory: ${dir}"
|
|
177
|
+
done
|
|
178
|
+
|
|
179
|
+
if [[ ${#PRUNED[@]} -eq 0 ]]; then
|
|
180
|
+
echo "No pre-release directories found for ${VERSION}."
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
- name: Commit switcher.json and pruned directories to gh-pages
|
|
184
|
+
run: |
|
|
185
|
+
cd gh-pages-clone
|
|
186
|
+
git config user.name "github-actions[bot]"
|
|
187
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
188
|
+
git add -A
|
|
189
|
+
git diff --cached --quiet || git commit -m "ci: release ${DOC_VERSION}: update switcher.json, prune pre-release docs (backfill)"
|
|
190
|
+
git pull --rebase origin gh-pages
|
|
191
|
+
git push
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
tags:
|
|
8
|
+
- '*'
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
|
|
20
|
+
build-pypi:
|
|
21
|
+
name: Build and publish to PyPI
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v6
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
|
|
29
|
+
- name: Set up Python
|
|
30
|
+
uses: actions/setup-python@v6
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
|
|
34
|
+
- name: Install build tools
|
|
35
|
+
run: pip install --upgrade build twine
|
|
36
|
+
|
|
37
|
+
- name: Build sdist and wheel
|
|
38
|
+
run: python -m build --sdist --wheel --outdir dist/ .
|
|
39
|
+
|
|
40
|
+
- name: Check package metadata
|
|
41
|
+
run: twine check dist/*
|
|
42
|
+
|
|
43
|
+
- name: Publish to PyPI
|
|
44
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
45
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
46
|
+
with:
|
|
47
|
+
verbose: true
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Unit Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: Python ${{ matrix.python-version }}
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
22
|
+
include:
|
|
23
|
+
# 3.14 is pre-release; run it for early warning but don't fail CI
|
|
24
|
+
- python-version: "3.14-dev"
|
|
25
|
+
continue-on-error: true
|
|
26
|
+
|
|
27
|
+
continue-on-error: ${{ matrix.continue-on-error == true }}
|
|
28
|
+
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v6
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 0 # full history so hatch-vcs can read git tags
|
|
33
|
+
|
|
34
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
35
|
+
uses: actions/setup-python@v6
|
|
36
|
+
with:
|
|
37
|
+
python-version: ${{ matrix.python-version }}
|
|
38
|
+
cache: pip
|
|
39
|
+
|
|
40
|
+
- name: Install package with dev dependencies
|
|
41
|
+
run: pip install -e .[dev]
|
|
42
|
+
|
|
43
|
+
- name: Run tests
|
|
44
|
+
run: python -m pytest -v
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
references/
|
|
2
|
+
src/ad_hoc_diffractometer/_version.py
|
|
3
|
+
docs/build/
|
|
4
|
+
docs/source/autoapi/
|
|
5
|
+
.coverage
|
|
6
|
+
htmlcov/
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
__pycache__/
|
|
9
|
+
*.py[cod]
|
|
10
|
+
*.egg-info/
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
*.egg
|
|
14
|
+
*.log
|
|
15
|
+
*.bak
|
|
16
|
+
*.swp
|
|
17
|
+
.DS_Store
|
|
18
|
+
.idea/
|
|
19
|
+
.vscode/
|
|
20
|
+
.loglogin
|
|
21
|
+
dev_*
|
|
22
|
+
dev_*/
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v5.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: trailing-whitespace
|
|
6
|
+
- id: end-of-file-fixer
|
|
7
|
+
- id: check-yaml
|
|
8
|
+
- id: check-toml
|
|
9
|
+
- id: check-merge-conflict
|
|
10
|
+
- id: debug-statements
|
|
11
|
+
|
|
12
|
+
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
|
13
|
+
rev: v1.5.5
|
|
14
|
+
hooks:
|
|
15
|
+
- id: insert-license
|
|
16
|
+
name: insert-license (src)
|
|
17
|
+
files: ^src/ad_hoc_diffractometer/(?!_version).*\.py$
|
|
18
|
+
args:
|
|
19
|
+
- --license-filepath=.copyright.txt
|
|
20
|
+
- --comment-style=#
|
|
21
|
+
- --no-extra-eol
|
|
22
|
+
- id: insert-license
|
|
23
|
+
name: insert-license (tests)
|
|
24
|
+
files: ^tests/test_.*\.py$
|
|
25
|
+
args:
|
|
26
|
+
- --license-filepath=.copyright.txt
|
|
27
|
+
- --comment-style=#
|
|
28
|
+
- --no-extra-eol
|
|
29
|
+
|
|
30
|
+
- repo: https://github.com/PyCQA/isort
|
|
31
|
+
rev: 5.13.2
|
|
32
|
+
hooks:
|
|
33
|
+
- id: isort
|
|
34
|
+
|
|
35
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
36
|
+
rev: v0.9.10
|
|
37
|
+
hooks:
|
|
38
|
+
- id: ruff
|
|
39
|
+
args: [--fix]
|
|
40
|
+
- id: ruff-format
|