-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathmakefile
More file actions
419 lines (364 loc) · 18.7 KB
/
Copy pathmakefile
File metadata and controls
419 lines (364 loc) · 18.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
# Emit pytest-xdist argument if available; can be overridden on the make command line
PYTEST_XDIST ?= $(shell python scripts/pytest_xdist.py 2>/dev/null)
PYTEST ?=
PYTHON ?= python3
WITH_MPMC ?= 0
HAS_MPMC ?= $(shell python -c "import importlib.util; mods=('torch','pyg_lib','torch_geometric'); print(int(all(importlib.util.find_spec(m) is not None for m in mods)))" 2>/dev/null || echo 0)
# set environment variable for documentation
export JUPYTER_PLATFORM_DIRS=1
##########################################################
# Coverage artifacts (local-only; should be gitignored)
##########################################################
ARTIFACTS_DIR ?= artifacts
COV_DIR ?= $(ARTIFACTS_DIR)/coverage
LOG_DIR ?= $(ARTIFACTS_DIR)/logs
UNIT_COV_DIR ?= $(COV_DIR)/unit
DOCTEST_COV_DIR ?= $(COV_DIR)/doctests
BOOKTEST_COV_DIR ?= $(COV_DIR)/booktests
ensure_artifacts:
@mkdir -p $(UNIT_COV_DIR) $(DOCTEST_COV_DIR) $(BOOKTEST_COV_DIR) $(LOG_DIR)
##########################################################
# utilities
##########################################################
# This helps locate generated or local-only folders like build, .pytest_cache, etc.
find_local_only_files:
chmod +x scripts/find_local_only_folders.sh
./scripts/find_local_only_folders.sh
clean_local_only_files:
rm -fr test/booktests/.ipynb_checkpoints/ .pytest_cache/ .ruff_cache/ __pycache__/ */__pycache__/ */*/__pycache__/ raw.githubusercontent.com/ */raw.githubusercontent.com/ */*/raw.githubusercontent.com/ site/ build/ .pdm-build/ artifacts/logs/ artifacts/booktests/ */*/logs/ */*/runinfo/
chmod +x scripts/find_local_only_folders.sh > /dev/null 2>&1
for f in $(shell ./scripts/find_local_only_folders.sh > /dev/null 2>&1); do \
rm -f "$$f"; > /dev/null 2>&1; \
done
clean_coverage:
rm -fr artifacts/coverage/ .coverage* test/booktests/.coverage*
##########################################################
# Doctests
##########################################################
doctests_minimal: ensure_artifacts
@mkdir -p $(DOCTEST_COV_DIR)/minimal
COVERAGE_FILE=$(DOCTEST_COV_DIR)/minimal/.coverage \
python -m pytest $(PYTEST_XDIST) -x --cov qmcpy/ --cov-report term --cov-report json:$(DOCTEST_COV_DIR)/minimal/coverage.json --no-header --cov-append \
--doctest-modules qmcpy/ \
--ignore qmcpy/fast_transform/ft_pytorch.py \
--ignore qmcpy/stopping_criterion/pf_gp_ci.py \
--ignore qmcpy/kernel/ \
--ignore qmcpy/util/dig_shift_invar_ops.py \
--ignore qmcpy/util/shift_invar_ops.py \
--ignore qmcpy/util/exact_gpytorch_gression_model.py \
--ignore qmcpy/integrand/umbridge_wrapper.py \
--ignore qmcpy/integrand/hartmann6d.py \
--ignore qmcpy/discrete_distribution/mpmc/ \
doctests_torch: ensure_artifacts
@mkdir -p $(DOCTEST_COV_DIR)/torch
COVERAGE_FILE=$(DOCTEST_COV_DIR)/torch/.coverage \
python -m pytest $(PYTEST_XDIST) -x --cov qmcpy/ --cov-report term --cov-report json:$(DOCTEST_COV_DIR)/torch/coverage.json --no-header --cov-append \
--doctest-modules qmcpy/fast_transform/ft_pytorch.py \
--doctest-modules qmcpy/kernel/*.py \
--doctest-modules qmcpy/util/dig_shift_invar_ops.py \
--doctest-modules qmcpy/util/shift_invar_ops.py \
doctests_gpytorch: ensure_artifacts
@mkdir -p $(DOCTEST_COV_DIR)/gpytorch
COVERAGE_FILE=$(DOCTEST_COV_DIR)/gpytorch/.coverage \
python -m pytest $(PYTEST_XDIST) -x --cov qmcpy/ --cov-report term --cov-report json:$(DOCTEST_COV_DIR)/gpytorch/coverage.json --no-header --cov-append \
--doctest-modules qmcpy/stopping_criterion/pf_gp_ci.py \
doctests_botorch: ensure_artifacts
@mkdir -p $(DOCTEST_COV_DIR)/botorch
COVERAGE_FILE=$(DOCTEST_COV_DIR)/botorch/.coverage \
python -m pytest $(PYTEST_XDIST) -x --cov qmcpy/ --cov-report term --cov-report json:$(DOCTEST_COV_DIR)/botorch/coverage.json --no-header --cov-append \
--doctest-modules qmcpy/integrand/hartmann6d.py \
doctests_mpmc:
@mkdir -p $(DOCTEST_COV_DIR)/mpmc
COVERAGE_FILE=$(DOCTEST_COV_DIR)/mpmc/.coverage \
python -m pytest $(PYTEST_XDIST) -x --cov qmcpy/ --cov-report term --cov-report json:$(DOCTEST_COV_DIR)/mpmc/coverage.json --no-header --cov-append \
--doctest-modules qmcpy/discrete_distribution/mpmc/*.py \
doctests_umbridge: ensure_artifacts # https://github.com/UM-Bridge/umbridge/issues/96
@mkdir -p $(DOCTEST_COV_DIR)/umbridge
@docker --version
COVERAGE_FILE=$(DOCTEST_COV_DIR)/umbridge/.coverage \
python -m pytest $(PYTEST_XDIST) -x --cov qmcpy/ --cov-report term --cov-report json:$(DOCTEST_COV_DIR)/umbridge/coverage.json --no-header --cov-append \
--doctest-modules qmcpy/integrand/umbridge_wrapper.py \
doctests_markdown:
@phmutest docs/*.md --replmode --log -c
doctests_no_docker_no_mpmc: doctests_minimal doctests_torch doctests_gpytorch doctests_botorch
doctests_no_docker: doctests_minimal doctests_torch doctests_gpytorch doctests_botorch doctests_mpmc
doctests_no_mpmc: doctests_minimal doctests_torch doctests_gpytorch doctests_botorch doctests_umbridge
doctests: doctests_markdown doctests_minimal doctests_torch doctests_gpytorch doctests_botorch doctests_umbridge doctests_mpmc
##########################################################
# Unit Tests in `test/` folder (OFFICIAL coverage)
##########################################################
unittests: ensure_artifacts
@mkdir -p $(UNIT_COV_DIR)
@PYTHON_BIN=$$(command -v python 2>/dev/null || { [ -n "$$CONDA_PREFIX" ] && command -v "$$CONDA_PREFIX/bin/python" 2>/dev/null; } || { command -v conda >/dev/null 2>&1 && conda run -n qmcpy python -c 'import sys; print(sys.executable)' 2>/dev/null; } || command -v python3 2>/dev/null); \
if [ -z "$$PYTHON_BIN" ]; then \
echo "No Python interpreter found (tried: python, $$CONDA_PREFIX/bin/python, python3)."; \
exit 127; \
fi; \
COVERAGE_FILE=$(UNIT_COV_DIR)/.coverage \
"$$PYTHON_BIN" -m pytest $(PYTEST_XDIST) -x $(PYTEST_EXTRA_ARGS) \
--cov=qmcpy \
--cov-report term \
--cov-report json:$(UNIT_COV_DIR)/coverage.json \
--no-header \
test/ -W ignore::DeprecationWarning
tests_no_docker_no_mpmc: doctests_no_docker_no_mpmc unittests coverage
##########################################################
# Unit Tests for `*.ipynb` in `demos/` folder
##########################################################
generate_booktests:
@echo "\nGenerating missing booktest files..."
cd test/booktests/ && python generate_test.py --check-missing
check_booktests:
rm -fr demos/.ipynb_checkpoints/*checkpoint.ipynb && \
find demos -name '*.ipynb' | while read nb; do \
base=$$(basename "$$nb" .ipynb); \
test_base=$$(echo "$$base" | sed 's/[-.]/_/g'); \
if echo "$$nb" | grep -q "Parslfest_2025"; then \
continue; \
fi; \
if ! ls test/booktests/tb_"$$test_base".py > /dev/null 2>&1; then \
echo " Missing test for: $$nb -> Expected: test/booktests/tb_$$test_base.py"; \
fi; \
done
@echo "Total notebooks: $$(find demos -name '*.ipynb' | wc -l)"
@echo "Total test files: $$(find test/booktests -name 'tb_*.py' | wc -l)"
tests_no_mpmc: doctests_no_mpmc unittests coverage
booktests_no_docker: check_booktests generate_booktests clean_local_only_files ensure_artifacts
@echo "\nNotebook tests"
@mkdir -p $(BOOKTEST_COV_DIR)
set -e && \
cd test/booktests/ && \
if [ -z "$(TESTS)" ]; then \
PYTHONWARNINGS="ignore::UserWarning,ignore::DeprecationWarning,ignore::FutureWarning,ignore::ImportWarning" \
COVERAGE_FILE=../../$(BOOKTEST_COV_DIR)/.coverage \
python -W ignore -m coverage run --append --source=../../qmcpy/ -m unittest discover -s . -p "*.py" -v --failfast; \
else \
PYTHONWARNINGS="ignore::UserWarning,ignore::DeprecationWarning,ignore::FutureWarning,ignore::ImportWarning" \
COVERAGE_FILE=../../$(BOOKTEST_COV_DIR)/.coverage \
python -W ignore -m coverage run --append --source=../../qmcpy/ -m unittest $(TESTS) -v --failfast; \
fi && \
cd ../..
# coverage is done in function run_single_test() in test/booktests/parsl_test_runner.py
booktests_parallel_no_docker: check_booktests generate_booktests clean_local_only_files
@echo "\nNotebook tests with Parsl"
cd test/booktests/ && \
rm -fr *.eps *.jpg *.pdf *.png *.part *.txt *.log && rm -fr logs && rm -fr runinfo prob_failure_gp_ci_plots && \
PYTHONWARNINGS="ignore::UserWarning,ignore::DeprecationWarning,ignore::FutureWarning,ignore::ImportWarning" \
python parsl_test_runner.py $(TESTS) -v --failfast && \
cd ../..
# Windows-compatible parallel booktests using pytest-xdist instead of Parsl
booktests_parallel_pytest: check_booktests generate_booktests clean_local_only_files ensure_artifacts
@mkdir -p $(BOOKTEST_COV_DIR)
cd test/booktests/ && \
PYTHONWARNINGS="ignore::UserWarning,ignore::DeprecationWarning,ignore::FutureWarning,ignore::ImportWarning" \
COVERAGE_FILE=../../$(BOOKTEST_COV_DIR)/.coverage \
python -W ignore -m pytest $(PYTEST_XDIST) $(PYTEST) -v tb_*.py \
--cov=qmcpy \
--cov-append \
--cov-report=term \
--cov-report=json:../../$(BOOKTEST_COV_DIR)/coverage.json && \
cd ../..
##########################################################
# Combinations of Above Tests
##########################################################
tests:
set -e && $(MAKE) doctests && $(MAKE) unittests && $(MAKE) coverage
tests_no_docker:
@echo "Running environment cleanup for invalid distributions (dry-run will be skipped, applying changes)..."
@if [ "$(WITH_MPMC)" = "1" ] || [ "$(HAS_MPMC)" = "1" ]; then \
DOCTESTS_TARGET=doctests_no_docker; \
UNITTESTS_ARGS=""; \
else \
DOCTESTS_TARGET=doctests_no_docker_no_mpmc; \
UNITTESTS_ARGS="--ignore=test/test_dd_mpmc.py"; \
fi && \
set -e && $(MAKE) $$DOCTESTS_TARGET && $(MAKE) unittests PYTEST_EXTRA_ARGS="$$UNITTESTS_ARGS"
# Fast test target: run doctests, unittests, booktests concurrently
tests_fast:
@echo "Running fast tests: doctests and unittests concurrently (splitting CPU cores)."
@make clean_local_only_files clean_coverage && \
if [ "$(WITH_MPMC)" = "1" ] || [ "$(HAS_MPMC)" = "1" ]; then \
DOCTESTS_TARGET=doctests_no_docker; \
UNITTESTS_ARGS=""; \
else \
DOCTESTS_TARGET=doctests_no_docker_no_mpmc; \
UNITTESTS_ARGS="--ignore=test/test_dd_mpmc.py"; \
fi && \
set -e && \
$(MAKE) $$DOCTESTS_TARGET & \
$(MAKE) unittests PYTEST_EXTRA_ARGS="$$UNITTESTS_ARGS" & \
$(MAKE) booktests_parallel_no_docker & \
wait
$(MAKE) coverage
##########################################################
# Local Coverage Reports and Tools
##########################################################
coverage: ensure_artifacts # https://github.com/marketplace/actions/coverage-badge
@echo ""
@echo "============================================================"
@echo "OFFICIAL COVERAGE REPORT (UNIT TESTS ONLY)"
@echo "Source: $(UNIT_COV_DIR)/.coverage"
@echo "Doctests and booktests are NOT included."
@echo "============================================================"
@echo ""
COVERAGE_FILE=$(UNIT_COV_DIR)/.coverage \
python -m coverage report -m
combine-coverage-local: ensure_artifacts # Combine coverage files and build reports locally (NOT official)
@echo "Combining coverage files from $(COV_DIR)/ into coverage-data/ and generating reports"
@mkdir -p coverage-data && \
rm -rf coverage-data/* && \
# Prefer new artifact layout first
find $(COV_DIR) -type f -name '.coverage*' -exec cp {} coverage-data/ \; 2>/dev/null || true; \
find $(COV_DIR) -type f -name 'coverage.json' -exec cp {} coverage-data/ \; 2>/dev/null || true; \
# Backwards-compat: if artifacts had nothing, try repo root
if [ -z "$$(find coverage-data -type f \( -name '.coverage*' -o -name 'coverage.json' \) 2>/dev/null)" ]; then \
echo "No coverage found under $(COV_DIR)/. Trying repo root (.coverage*, coverage.json) ..."; \
cp -r .coverage* coverage.json coverage-data/ 2>/dev/null || true; \
fi; \
# Final check: must have something to combine
if [ -z "$$(find coverage-data -type f -name '.coverage*' 2>/dev/null)" ]; then \
echo "No coverage data found. Run tests first (e.g., make unittests / make doctests / make booktests_*)"; \
exit 1; \
fi; \
python scripts/combine_coverage.py --dir coverage-data --outdir coverage_html --keep
coverage_html: ensure_artifacts
@mkdir -p $(UNIT_COV_DIR)/html
@echo ""
@echo "============================================================"
@echo "GENERATING UNIT TEST COVERAGE HTML (OFFICIAL)"
@echo "Output: $(UNIT_COV_DIR)/html/index.html"
@echo "============================================================"
@echo ""
COVERAGE_FILE=$(UNIT_COV_DIR)/.coverage \
python -m coverage html -d $(UNIT_COV_DIR)/html
delcoverage:
@rm -f .coverage coverage.json test/booktests/.coverage
@rm -rf $(COV_DIR)
@rm -rf .pytest_cache
##########################################################
# Make UML class diagrams
##########################################################
uml:
# UML Diagrams
# Discrete Distributions
@pyreverse -k qmcpy/discrete_distribution/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/discrete_distribution_overview.svg
# Discrete Distribution Specific
@pyreverse qmcpy/discrete_distribution/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/discrete_distribution_specific.svg
# True Measure Overview
@pyreverse -k qmcpy/true_measure/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/true_measure_overview.svg
# True Measure Specific
@pyreverse qmcpy/true_measure/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/true_measure_specific.svg
# Integrand Overview
@pyreverse -k qmcpy/integrand/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/integrand_overview.svg
# Integrand Specific
@pyreverse qmcpy/integrand/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/integrand_specific.svg
# Stopping Criterion Overview
@pyreverse -k qmcpy/stopping_criterion/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/stopping_criterion_overview.svg
# Stopping Criterion Specific
@pyreverse qmcpy/stopping_criterion/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/stopping_criterion_specific.svg
# Kernel Overview
@pyreverse -k qmcpy/kernel/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/kernel_overview.svg
# Kernel Specific
@pyreverse qmcpy/kernel/ -o svg 1>/dev/null && mv classes.svg docs/api/umls/kernel_specific.svg
##########################################################
# Documentation with `mkdocs`
#
# Run `mkdocs build -v` to debug. It generates HTML in the site/ folder.
# You can enter `open site/index.html` to open the local pages in a browser.
# (However, the search function may be slow.)
#
# Use `mkdocs serve` to run a local server. The webpages are stored in a temporary folder and will be deleted when the server is stopped.
##########################################################
copydocs: # mkdocs only looks for content in the docs/ folder, so we have to copy it there
@rm -rf docs/paper docs/demos
@cp README.md docs/README.md
@cp AGENTS.md docs/AGENTS.md
@perl -0pi -e 's!\(docs/good_practices\.md\)!\(good_practices.md\)!g' docs/AGENTS.md
@perl -0pi -e 's!\(docs/ai-assisted-contributions\.md\)!\(ai-assisted-contributions.md\)!g' docs/AGENTS.md
@perl -0pi -e 's!\(docs/RELEASE\.md\)!\(RELEASE.md\)!g' docs/AGENTS.md
@perl -0pi -e 's!\(docs/assets/pep8-badge\.svg\)!\(assets/pep8-badge.svg\)!g' docs/README.md
@perl -0pi -e 's!\(docs/qmc-software\.md\)!\(qmc-software.md\)!g' docs/README.md
@cp CONTRIBUTING.md docs/CONTRIBUTING.md
@# Rewrite repo-root-relative link for the copied MkDocs page.
@perl -0pi -e 's!\(docs/good_practices\.md\)!\(good_practices.md\)!g' docs/CONTRIBUTING.md
@perl -0pi -e 's!\(docs/ai-assisted-contributions\.md\)!\(ai-assisted-contributions.md\)!g' docs/CONTRIBUTING.md
@cp community.md docs/community.md
@cp -r demos docs
@find docs/demos -mindepth 2 -name README.md -delete
@cp -r paper docs
@rm -f docs/paper/README.md
@./scripts/render_paper_for_mkdocs.sh
@cp test/booktests/README.md docs/booktests.md
@cp test/README.md docs/tests.md
@python scripts/make_qmc_software_page.py
@mkdir -p docs/stats
@cp stats/pypi_downloads.md docs/stats/pypi_downloads.md
@cp docs/assets/logos/qmcpy_logo.png docs/apple-touch-icon.png
@cp docs/assets/logos/qmcpy_logo.png docs/apple-touch-icon-precomposed.png
@cp docs/assets/logos/qmcpy_logo.png docs/favicon.ico
@cp QMCPy_Shared_Leadership.md docs/
runmkdocserve:
@PORT=$${MKDOCS_PORT:-8000}; \
while lsof -iTCP:$$PORT -sTCP:LISTEN >/dev/null 2>&1; do \
PORT=$$((PORT+1)); \
done; \
echo "Starting mkdocs on http://127.0.0.1:$$PORT"; \
NO_MKDOCS_2_WARNING=1 JUPYTER_PLATFORM_DIRS=1 mkdocs serve -a 127.0.0.1:$$PORT
NO_MKDOCS_2_WARNING=1 JUPYTER_PLATFORM_DIRS=1 mkdocs serve -a 127.0.0.1:$$PORT
doc: uml copydocs runmkdocserve
docnouml: copydocs runmkdocserve
check_links: copydocs # internal links + anchors only; fast, no network, safe for CI
@NO_MKDOCS_2_WARNING=1 mkdocs build -q -d site
@python scripts/check_links.py site
check_links_external: copydocs # also checks http/https links; slow and network-flaky, run locally
@NO_MKDOCS_2_WARNING=1 mkdocs build -q -d site
@python scripts/check_links.py site --external
# The targets above check links inside the new site; these check the other
# direction -- already-published URLs that would 404 after the next deploy.
check_removed_urls: copydocs # fetches the deployed sitemap.xml; needs network
@python scripts/check_removed_urls.py
check_removed_urls_verify: copydocs # also HTTP-checks every redirect target
@python scripts/check_removed_urls.py --verify-redirects
##########################################################
# PEP8
##########################################################
PYLINT ?= pylint
PYLINT_BASE ?= develop
check_pep8:
@$(PYLINT) qmcpy --exit-zero --disable=R,C,E0401 --ignored-modules=qmctoolscl
check_pep8_changed:
@set -e; \
changed_files="$$( \
{ \
git diff --name-only --diff-filter=ACMR "$(PYLINT_BASE)...HEAD" -- '*.py'; \
git diff --name-only --diff-filter=ACMR HEAD -- '*.py'; \
git ls-files --others --exclude-standard -- '*.py'; \
} | sort -u \
)"; \
if [ -z "$$changed_files" ]; then \
echo "No changed Python files relative to $(PYLINT_BASE)."; \
else \
echo "Running pylint on changed Python files relative to $(PYLINT_BASE):"; \
printf '%s\n' "$$changed_files"; \
$(PYLINT) --disable=R,C,E0401 --ignored-modules=qmctoolscl $$changed_files; \
fi
pep8: update_pep8_badge
update_pep8_badge:
@mkdir -p $(LOG_DIR) docs/assets
@make check_pep8 > $(LOG_DIR)/pylint.out
@python3 scripts/update_pep8_badge.py $(LOG_DIR)/pylint.out docs/assets/pep8-badge.json docs/assets/pep8-badge.svg
##########################################################
# Formatting
##########################################################
FORMAT_PATH ?= .
MARKDOWN_UNWRAP_PATH ?= $(FORMAT_PATH)
format:
$(MAKE) flatten_qmcpy_imports
$(MAKE) markdown-unwrap MARKDOWN_UNWRAP_PATH="$(MARKDOWN_UNWRAP_PATH)"
$(MAKE) rm_trailing_whitespace FORMAT_PATH="$(FORMAT_PATH)"
flatten_qmcpy_imports:
$(PYTHON) scripts/flatten_qmcpy_imports.py
markdown-unwrap:
$(PYTHON) scripts/unwrap_markdown.py "$(MARKDOWN_UNWRAP_PATH)"
rm_trailing_whitespace:
$(PYTHON) scripts/remove_trailing_whitespace.py "$(FORMAT_PATH)"