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 @@