diff --git a/.github/workflows/test-webview-client.yaml b/.github/workflows/test-webview-client.yaml
index ecfd2afa..b7a9d1ea 100644
--- a/.github/workflows/test-webview-client.yaml
+++ b/.github/workflows/test-webview-client.yaml
@@ -56,20 +56,35 @@ jobs:
run: bun run test:lint
# test that app has no typescript errors
-# test-types:
-# runs-on: ubuntu-latest
-# steps:
-# - name: Checkout code
-# uses: actions/checkout@v4
+ test-types:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
-# - name: Set up Bun
-# uses: oven-sh/setup-bun@v2
+ - name: Checkout bumps source
+ uses: actions/checkout@v4
+ with:
+ repository: bumps/bumps
+ sparse-checkout: 'bumps/webview/client'
+ path: bumps
-# - name: Install packages
-# run: bun install
+ - name: Set up Bun
+ uses: oven-sh/setup-bun@v2
-# - name: Run test
-# run: bun run test:types
+ - name: Install packages
+ run: bun install
+
+ - name: Use bumps code from source
+ run: |
+ cd ../../../bumps/bumps/webview/client
+ bun install
+ bun link
+ cd ../../../../refl1d/webview/client
+ bun link bumps-webview-client
+
+ - name: Run test
+ run: bun run test:types
# run unit tests
# test-unit:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 02975a96..47e31884 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -16,7 +16,7 @@ repos:
# - id: end-of-file-fixer
# - id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.7.2
+ rev: v0.8.6
hooks:
# - id: ruff
# args: [--fix, --exit-non-zero-on-fix]
diff --git a/Makefile b/Makefile
index b546f189..6bbf047f 100644
--- a/Makefile
+++ b/Makefile
@@ -30,6 +30,19 @@ test: ## Run pytest and doc tests
pytest -v
python check_examples.py --chisq
+#######################
+### Dev environment ###
+#######################
+
+.PHONY: dev-backend
+dev-backend: ## Start the backend server in headless mode
+ refl1d-webview --port 8080 --headless
+
+.PHONY: dev-frontend
+dev-frontend: ## Start the frontend server in development mode
+ cd refl1d/webview/client && \
+ $(FE_CMD) run dev
+
##############################
### Linting and formatting ###
##############################
@@ -37,6 +50,10 @@ test: ## Run pytest and doc tests
.PHONY: lint
lint: lint-backend lint-frontend ## Run all linters
+.PHONY: lint-backend-check
+lint-backend-check: ## Run ruff linting on python code
+ @ruff check bumps/ run.py test.py check_*.py
+
.PHONY: lint-backend
lint-backend: ## Run ruff linting on python code
@ruff check --fix refl1d/ tests/ setup.py
diff --git a/README.rst b/README.rst
index b1254911..4e801b60 100755
--- a/README.rst
+++ b/README.rst
@@ -1,7 +1,7 @@
Refl1D
======
-Refl1D is a program for analyzing 1D reflectometry measurements made with
+Refl1D is a program for analyzing 1-D reflectometry measurements made with
X-ray and neutron beamlines. The 1-D models give the depth profile for
material scattering density composed of a mixture of flat and continuously
varying freeform layers. With polarized neutron measurements, scientists
diff --git a/pyproject.toml b/pyproject.toml
index 91876fe2..11c0fa70 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,22 +22,24 @@ classifiers = [
]
requires-python = ">=3.9"
dependencies = [
- "bumps>=1.0.0a11",
+ "bumps>=1.0.0a12",
"matplotlib",
"numba",
"numpy",
"periodictable",
"scipy",
+ "orsopy"
]
[project.optional-dependencies]
dev = [
+ "matplotlib", # for testing
"pre-commit",
"pydantic",
"pytest",
"pytest-cov",
"ruff",
- "sphinx",
+ "sphinx < 8.2",
"versioningit",
]
full = ["wxpython", "ipython"]
@@ -74,13 +76,15 @@ script-files = ["bin/refl1d_cli.py", "bin/refl1d_gui.py"]
[tool.setuptools.packages.find]
where = ["."]
+include = ["refl1d*"]
[project.scripts]
refl1d = "refl1d.main:cli"
refl1d-webview = "refl1d.webview.server.webserver:main"
[tool.pytest.ini_options]
-addopts = "--doctest-modules --doctest-glob=*.rst --cov=refl1d"
+# TODO: remove --assert=plain when https://github.com/scipy/scipy/issues/22236 is resolved
+addopts = "--doctest-modules --doctest-glob=*.rst --cov=bumps --assert=plain"
doctest_optionflags = ["ELLIPSIS", "NORMALIZE_WHITESPACE"]
testpaths = ["refl1d", "tests", "doc/getting_started", "doc/guide"]
norecursedirs = ["view", "mystic", "bin", "webview/client", "explore"]
diff --git a/refl1d/probe/data_loaders/load4.py b/refl1d/probe/data_loaders/load4.py
index 88014ceb..50299499 100644
--- a/refl1d/probe/data_loaders/load4.py
+++ b/refl1d/probe/data_loaders/load4.py
@@ -1,10 +1,13 @@
+# standard imports
import json
-import numpy as np
+# third party imports
from bumps.data import parse_multi, strip_quotes
+import numpy as np
+from orsopy.fileio.orso import load_nexus, load_orso
-from ...sample.reflectivity import BASE_GUIDE_ANGLE
-from ..probe import (
+# refl1d imports
+from refl1d.probe import (
NeutronProbe,
PolarizedNeutronProbe,
PolarizedQProbe,
@@ -12,18 +15,36 @@
QProbe,
XrayProbe,
)
-from ..resolution import QL2T, QT2L, FWHM2sigma, dQdL2dT, dQdT2dLoL, sigma2FWHM
+from refl1d.probe.resolution import QL2T, QT2L, FWHM2sigma, dQdL2dT, dQdT2dLoL, sigma2FWHM
+from refl1d.sample.reflectivity import BASE_GUIDE_ANGLE
-def parse_orso(filename, *args, **kwargs):
- """load an ORSO text (.ort) or binary (.orb) file"""
+def parse_orso(filename):
+ """
+ Load an ORSO text (.ort) or binary (.orb) file containing one or more datasets
+
+ Parameters
+ ----------
+ filename : str
+ The path to the ORSO file to be loaded.
+
+ Returns
+ -------
+ list of tuple
+ A list of tuples, each containing a header dictionary and a data array derived from each loaded dataset.
+ The header dictionary contains metadata about the measurement,
+ and the data array contains the measurement data.
+
+ Notes
+ -----
+ The function supports both ORSO text (.ort) and binary (.orb) files.
+ The polarization information is converted using a predefined mapping.
+ The header dictionary includes keys for polarization, angle, angular resolution,
+ wavelength, and wavelength resolution.
+ """
if filename.endswith(".ort"):
- from orsopy.fileio.orso import load_orso
-
entries = load_orso(filename)
elif filename.endswith(".orb"):
- from orsopy.fileio.orso import load_nexus
-
entries = load_nexus(filename)
POL_CONVERSION = {
@@ -45,6 +66,23 @@ def parse_orso(filename, *args, **kwargs):
header_out = {"polarization": polarization}
def get_key(orso_name, refl1d_name, refl1d_resolution_name):
+ """
+ Extract value and error from one of the ORSO columns. If no column corresponding
+ to entry `orso_name` is found, search in the instrument settings.
+
+ Parameters
+ ----------
+ orso_name : str
+ The name of the ORSO column or instrument setting to extract.
+ refl1d_name : str
+ The corresponding refl1d name for the value of entry `orso_name`
+ refl1d_resolution_name : str
+ The corresponding refl1d error name the error of entry `orso_name`
+
+ Notes
+ -----
+ This function requires the instrument setting `orso_name` to have a "magnitue" and "error" attribute.
+ """
column_index = next(
(i for i, c in enumerate(columns) if getattr(c, "physical_quantity", None) == orso_name),
None,
diff --git a/refl1d/sample/layers.py b/refl1d/sample/layers.py
index 0f771f9e..983f8924 100644
--- a/refl1d/sample/layers.py
+++ b/refl1d/sample/layers.py
@@ -224,6 +224,7 @@ def __repr__(self):
@dataclass(init=False)
class Stack(Layer):
+ # TODO: Finish this docstring
"""
Reflectometry layer stack
diff --git a/refl1d/webview/build_client.py b/refl1d/webview/build_client.py
index 6699659b..9310e0b3 100644
--- a/refl1d/webview/build_client.py
+++ b/refl1d/webview/build_client.py
@@ -34,7 +34,7 @@ def cleanup_bumps_packages():
cleanup_bumps_packages()
bumps_path = Path(bumps.webview.__file__).parent / "client"
# pack it up for install...
- os.system(f"npm pack {bumps_path}")
+ os.system(f"npm pack {bumps_path} --quiet")
# get the package filename:
bumps_package_file = next(client_folder.glob("bumps-webview-client*.tgz"))
os.system(f"npm install {bumps_package_file} --no-save")
diff --git a/refl1d/webview/client/eslint.config.js b/refl1d/webview/client/eslint.config.js
index 03b71f26..5e5d8e79 100644
--- a/refl1d/webview/client/eslint.config.js
+++ b/refl1d/webview/client/eslint.config.js
@@ -1,10 +1,10 @@
+import url from "url";
+import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
+import pluginVue from "eslint-plugin-vue";
import { FlatCompat } from "@eslint/eslintrc";
import js from "@eslint/js";
import prettierConfig from "@vue/eslint-config-prettier";
import vueTsEslintConfig from "@vue/eslint-config-typescript";
-import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
-import pluginVue from "eslint-plugin-vue";
-import url from "url";
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
const compat = new FlatCompat({
@@ -35,6 +35,10 @@ export default [
"prefer-const": 0,
"@typescript-eslint/ban-ts-comment": ["error", { "ts-ignore": "allow-with-description" }],
"@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-unused-expressions": [
+ "error",
+ { allowShortCircuit: true, allowTernary: true }, // Temporary fix for indirect dependency @typescript-eslint <= 8.15.0
+ ],
"prettier/prettier": [
"warn",
{},
diff --git a/refl1d/webview/client/package.json b/refl1d/webview/client/package.json
index d708a3a6..fdf80a9f 100644
--- a/refl1d/webview/client/package.json
+++ b/refl1d/webview/client/package.json
@@ -14,37 +14,39 @@
"preview": "vite preview --port 4173",
"format": "prettier --write src",
"lint": "eslint src --fix",
- "test:lint": "eslint src"
+ "test:lint": "eslint src",
+ "test:types": "vue-tsc --noEmit --skipLibCheck -p tsconfig.json --composite false"
},
"dependencies": {
"bootstrap": "^5.3.3",
"bumps-webview-client": "^0.1.20",
"comlink": "^4.4.2",
"json-difference": "^1.16.1",
- "plotly.js": "^2.35.2",
+ "plotly.js": "^2.35.3",
"socket.io-client": "^4.8.1",
- "uuid": "^11.0.3",
+ "uuid": "^11.0.5",
"vue": "^3.5.13"
},
"devDependencies": {
- "@ianvs/prettier-plugin-sort-imports": "^4.4.0",
- "@types/plotly.js": "^2.35.0",
+ "@tsconfig/node22": "22.0.0",
+ "@types/plotly.js": "^2.35.1",
"@types/uuid": "^10.0.0",
- "@vitejs/plugin-vue": "^5.2.0",
+ "@vitejs/plugin-vue": "^5.2.1",
+ "@vue/tsconfig": "^0.7.0",
"@vue/eslint-config-prettier": "10.1.0",
- "@vue/eslint-config-typescript": "^14.1.3",
- "eslint": "9.14.0",
- "eslint-config-prettier": "^9.1.0",
+ "@vue/eslint-config-typescript": "^14.2.0",
+ "typescript": "^5.7.3",
+ "vite": "^6.0.7",
+ "vite-svg-loader": "5.1.0",
+ "vue-tsc": "^2.2.0",
+ "eslint": "^9.18.0",
+ "eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.1",
- "eslint-plugin-vue": "^9.31.0",
+ "eslint-plugin-vue": "^9.32.0",
"eslint-plugin-vuejs-accessibility": "^2.4.1",
- "prettier": "^3.3.3",
+ "prettier": "^3.4.2",
"prettier-plugin-css-order": "^2.1.2",
- "prettier-plugin-jsdoc": "^1.3.0",
- "vite": "^5.4.11",
- "vite-svg-loader": "^5.1.0"
- },
- "trustedDependencies": [
- "es5-ext"
- ]
+ "prettier-plugin-jsdoc": "^1.3.2",
+ "@ianvs/prettier-plugin-sort-imports": "^4.4.1"
+ }
}
diff --git a/refl1d/webview/client/prettier.config.js b/refl1d/webview/client/prettier.config.js
index 47565cd2..7eb290c5 100644
--- a/refl1d/webview/client/prettier.config.js
+++ b/refl1d/webview/client/prettier.config.js
@@ -1,43 +1,24 @@
/**
- * @see https://prettier.io/docs/en/configuration.html
* @type {import("prettier").Config}
+ * @see https://prettier.io/docs/en/configuration.html
*/
-// module.exports ={
-// "plugins": [
-// "@ianvs/prettier-plugin-sort-imports",
-// "./node_modules/prettier-plugin-jsdoc/dist/index.js",
-// "prettier-plugin-css-order"
-// ],
-// "importOrder": ["^vue", "^[a-zA-Z]", "^@[a-zA-Z]", "^@/", "^./", "^../"],
-// "cssDeclarationSorterOrder": "smacss",
-// "jsdocCapitalizeDescription": false,
-// "overrides": [
-// {
-// "files": "*.svg",
-// "options": {
-// "parser": "html"
-// }
-// }
-// ]
-// }
-
const config = {
- "plugins": [
+ plugins: [
"@ianvs/prettier-plugin-sort-imports",
"./node_modules/prettier-plugin-jsdoc/dist/index.js",
- "prettier-plugin-css-order"
+ "prettier-plugin-css-order",
],
- "importOrder": ["^vue", "^[a-zA-Z]", "^@[a-zA-Z]", "^@/", "^./", "^../"],
- "cssDeclarationSorterOrder": "smacss",
- "jsdocCapitalizeDescription": false,
- "overrides": [
+ importOrder: ["^vue", "^[a-zA-Z]", "^@[a-zA-Z]", "^@/", "^./", "^../"],
+ cssDeclarationSorterOrder: "smacss",
+ jsdocCapitalizeDescription: false,
+ overrides: [
{
- "files": "*.svg",
- "options": {
- "parser": "html"
- }
- }
+ files: "*.svg",
+ options: {
+ parser: "html",
+ },
+ },
],
experimentalTernaries: true,
printWidth: 120,
diff --git a/refl1d/webview/client/src/components/DataView.vue b/refl1d/webview/client/src/components/DataView.vue
index 85229000..05850276 100644
--- a/refl1d/webview/client/src/components/DataView.vue
+++ b/refl1d/webview/client/src/components/DataView.vue
@@ -1,7 +1,7 @@
@@ -69,7 +76,7 @@ function toggle_multiple() {
-