Brief notes describing each release and what's new.
Project milestones describe future plans.
Release expected by 2026-H2.
benchmark(): addsnapshot=True(default) to time on a simulator built from the diffractometer's configuration, and reportfwd/invratio. (:issue:`369`, :issue:`373`)Solver.default_geometry()andSolver.default_mode(geometry); remove hardcoded"E4CV"fallback insimulator_from_config(). (:issue:`372`)
- Add
benchmarktohklpy2.utils.__all__so its API page renders. (:issue:`375`)
Released 2026-04-16.
- Rename
creator_from_config()tosimulator_from_config()to clarify that it always produces a simulator with no hardware connections. (:issue:`363`)
- Add analyzer how-to guide: crystal analyzer as additional positioners on the detector arm, including save/restore. (:issue:`222`)
- Add how-to guide: all accepted forms for specifying real and pseudo axis positions (positional, keyword, dict, named tuple, bare tuple). (:issue:`358`)
- Save solver mode in
export()config;simulator_from_config()restores it automatically;restore()warns when saved mode differs from current mode, with opt-inrestore_mode=True. (:issue:`363`) - Save auxiliary axes in
export()config;simulator_from_config()restores them automatically. (:issue:`361`) - Add performance guide: factors affecting
forward()/inverse()throughput for diffractometer users. (:issue:`221`)
- Add
forward()andinverse()throughput benchmark (test_i221.py) establishing 183 ops/sec baseline; target ≥2,000 ops/sec. (:issue:`221`) - Remove
_api_demo.ipynbearly-development scratch notebook; content now covered by existing guides. (:issue:`367`)
- Fix
forward()throughput: from ~183 to >2,000 ops/sec viaconvert_units()short-circuit,axes_xref_reversedcache, and eliminating doubleupdate_solver()per call. (:issue:`221`) - Fix stale
from hklpy2.misc importinhkl_soleil-ub_set.ipynb(nowhklpy2.utils). (:issue:`353`) - Fix
AttributeErrorraised by non-hkl_soleilsolvers whenforward()callsset_reals(): add no-opset_reals()toSolverBase. (:issue:`347`) - Fix silent UB loss in non-
hkl_soleilsolvers: addUandUBgetter/setter pair toSolverBasethat stores orientation state. (:issue:`348`)
- Deprecate
move_zoneandscan_zoneimports fromhklpy2.blocks.zone; usehklpy2.plansinstead. (:issue:`339`)
- Extract all custom exception classes from
misc.pyinto newhklpy2/exceptions.py; update all internal imports to usehklpy2.exceptionsdirectly. (:issue:`341`) - Extract ophyd device construction helpers from
misc.pyinto newhklpy2/devices.py:VirtualPositionerBase,define_real_axis,dict_device_factory,dynamic_import,make_component,make_dynamic_instance,parse_factory_axes. (:issue:`342`) - Extract run-engine/databroker integration from
misc.pyinto newhklpy2/run_utils.py:ConfigurationRunWrapper,simulator_from_config,get_run_orientation,list_orientation_runs. (:issue:`344`) - Extract solver discovery machinery from
misc.pyinto newhklpy2/solver_utils.py:SOLVER_ENTRYPOINT_GROUP,get_solver,solver_factory,solvers. (:issue:`343`) - Add cross-references between
hkl_soleil-ub_calc.ipynb,hkl_soleil-ub_set.ipynb, andhow_calc_ub.rst; use named motor positions (dict(omega=…)) in notebook examples. (:issue:`353`) - Rename remaining
misc.pyutilities tohklpy2/utils.pyand deletemisc.py; renametest_misc.pytotest_utils.py. Completes themisc.pyrefactor. (:issue:`345`, closes :issue:`340`) - Move
move_zoneandscan_zoneplans fromhklpy2.blocks.zonetohklpy2.plans(canonical plan location). (:issue:`339`)
Released 2026-04-15.
patch-up release per standard release procedure
Released 2026-04-15.
- Add Diátaxis tutorial for E4CV: create, orient, and scan. (:issue:`318`)
- Add how-to guide: azimuthal (ψ) scans via
psi_constantmode. (:issue:`188`) - Add how-to guide: UB matrix computation and management. (:issue:`315`)
- Add how-to guide: :mod:`hklpy2.user` interactive interface. (:issue:`316`)
- Add how-to guide: zone scans (
move_zone,scan_zone). (:issue:`324`) - Add
scan_psi()convenience plan for azimuthal (ψ) scans with solver-agnostic mode discovery. (:issue:`335`)
- Fix
examples/hkl_soleil-e6c-psi.ipynb: full axis constraints, phi discontinuity, pre-scan verification, matplotlib plot. (:issue:`337`) - Automate
diffractometers.rstregeneration via solver-version sentinel and Sphinxbuilder-initedhook. (:issue:`331`) - Improve
concepts/lattice.rstandconcepts/wavelength.rst: explanatory prose,seealsolinks, crystal-systems cross-reference. (:issue:`325`) - Update
quickstart.rstas installation-verification entry point. (:issue:`327`) - Update
faq.rst: replace duplicated answers with cross-references. (:issue:`326`) - Restructure
guides/diffract.rstas "How to Work with a Diffractometer". (:issue:`317`) - Reframe
examples/as demonstrations; reorganiseguides/with Developer / Contributor section. (:issue:`314`)
Released 2026-04-14.
- Add how-to guide for constraints: setting axis limits, cut points,
using both together, resetting to defaults, and writing a custom
ConstraintBasesubclass. (:issue:`191`) - Add per-axis cut-point (angle branch-cut) to
LimitsConstraint: thecut_pointattribute maps computed angles into the range fromcup to (but not including)c + 360before limit checking inCore.forward(). Default is-180(range −180 up to +180), matching SPECcutsand diffcalcsetcutsemantics. (:issue:`296`) - Add
GeometryDescriptordataclass tohklpy2.backends.typing: decouples geometry identity (axis names, modes, description) from the solver backend that implements the mathematics. (:issue:`293`) - Add
SolverBase._geometry_registryandSolverBase.register_geometry()so solver subclasses can register geometries dynamically at runtime, enabling user-defined and ad-hoc diffractometer geometries. (:issue:`292`) - Refactor
ThTthSolverto use the new registry:geometries(),pseudo_axis_names,real_axis_names,modes, andextra_axis_namesare all driven by registeredGeometryDescriptorobjects instead of hard-coded string dispatch. (:issue:`292`, :issue:`293`)
- Fix CI test failure on Python 3.14:
TypeErrormessage forinoperator on non-iterable changed from"is not iterable"to"is not a container or iterable". Truncate match pattern to accept both. (:issue:`304`)
- Add Deprecated as a new
runtime dependency (conda-forge:
deprecated). Apply@versionadded,@versionchanged, and@deprecateddecorators throughout the codebase to document when each public symbol was introduced or changed. (:issue:`111`) - Clarify the
forward()contract: a solver may return one or more solutions in the list, and a single-element list is valid. Document backend library requirements for writing a solver. (:issue:`294`) - Document
ConstraintBase.valid()internals, theforward()call sequence, and theLimitsConstraintlabel requirement; clarify that hklpy2 constraints are post-computation filters distinct from SPEC/diffcalc cut points. (:issue:`275`) - Expand backend library requirements documentation: add reflection
management (required), optional capabilities (lattice refinement,
multi-solution, modes), and design rationale explaining why these
cannot be factored into
SolverBase. (:issue:`300`) - Migrate glossary from field-list format to Sphinx
.. glossary::directive, enabling:term:cross-references throughout the docs. (:issue:`305`) - Split the monolithic architecture
.. graphviz::diagram in__overview.rstinto four pre-built SVG figures (overview, user, core, solvers); DOT source files are committed alongside the SVGs indocs/source/_static/. Removes the Graphviz dependency from the Sphinx build. (:issue:`311`)
Released 2026-04-07.
- Add custom autoapi templates for concise page titles (short name as
heading, full import path in monospace
Import:line below), and addImport:line for classes and functions. (:issue:`251`) - Add
Full API Referencecard to the User Guide index. (:issue:`251`) - Hide
sig-prenamevia CSS; styleimport-pathcontainer. (:issue:`251`)
- Add
concepts/presets.rstconcepts page; updateconcepts/constraints.rstwith the presets/constraints distinction and mutual cross-references. (:issue:`259`) - Move design and checklist planning docs from
concepts/planning/toguides/; enrichguides.rstandexamples.rstlanding pages with categorized content tables. (:issue:`259`) - Expand FAQ with units table, no-solutions diagnosis, constraints vs. presets comparison, UB-matrix troubleshooting, SPEC command equivalents, and azimuthal scan note. (:issue:`259`)
- Revise concepts documents to be brief and purely conceptual; move
migration.rstfromconcepts/toguides/and remove guide-like example content fromops.rst. (:issue:`259`)
Released 2026-04-06.
- Add :func:`~hklpy2.blocks.zone.move_zone` plan (SPEC
mzequivalent): move diffractometer to a pseudo position in the zone. (:issue:`273`) - Export :class:`~hklpy2.blocks.zone.OrthonormalZone` and
:func:`~hklpy2.blocks.zone.move_zone` from the top-level
hklpy2package. (:issue:`273`)
- Fix :meth:`~hklpy2.backends.th_tth_q.ThTthSolver.removeAllReflections`
to clear reflections list and reset wavelength instead of raising
NotImplementedError. (:issue:`267`) - Remove unused
INPUT_VECTORandNUMERICre-exports frommisc.py; nothing imported them from there. (:issue:`267`) - Fix metadata dict bug in :func:`~hklpy2.blocks.zone.scan_zone`: the
dict(...).update(...)pattern always returnedNone; replaced with unpacking syntax. (:issue:`273`)
- Move
from .typing import ...statements inmisc.pyto the top-level import section; drop all# noqa: E402, F401suppressions from those lines; remove the backward-compatibility re-export comment block and docstring mention. (:issue:`283`) - Update
spec_xref.rstto replaceTODOplaceholders forcz,mz,pl, andszSPEC zone commands with correct hklpy2 references. (:issue:`273`) - Expand
test_summary_dictandtest_summaryintest_hkl_soleil.pyto assert keys, values, columns, and rows. (:issue:`269`) - Add reflection comparison assertions (pseudo, real, wavelength) in
test_configure.pyrestore test. (:issue:`270`) - Address CodeQL findings:
- Unused local variables:
lattice.py,test_lattice.py; restructure try/except inlattice.pyto initializebeta_val/gamma_valbefore the block. - Unused imports: add
# noqa: F401toTYPE_CHECKING-guarded imports inmisc.py,ops.py; remove unusedTYPE_CHECKING/Coreblock fromreflection.py(replaced annotation withOptional[Any]); restore accidentally removedINPUT_VECTOR,NamedFloatDict,NUMERICre-exports inmisc.py; remove unused import fromhkl_soleil-python_api.py; fix mixedimportandfrom ... importofhklpy2intest_isn_libhkl.py. - Mixed explicit/implicit returns: update return-type annotations and
fix fall-through returns in
base.py,hkl_soleil.py,no_op.py,ops.py,th_tth_q.py, anduser.py. - Variable defined multiple times: fix loop variables in
ops.py,user.py,test_backends.py,test_diffract.py, andtest_sample.py. - Modification of parameter with mutable default: fix
beam_kwargsandextrasindiffract.pyanduser.py; suppress B006 with# noqafor read-only mutable defaults where changing the default would alter runtime semantics. - Use of return value of a procedure: drop
tbl =assignment forpa()andwh()calls intest_user.py. - Unused global variable: remove
_I243_REAL_AXESfromtest_i210.py; addlogger.debug()calls throughoutmisc.pyto activate the previously unusedlogger. - File not always closed: use a
withblock inload_yaml_file()inmisc.py. __eq__not overridden when adding attributes: add__eq__toReflectionsDictinreflection.py.- Redundant comparison: remove from
test_lattice.pytest_equal(). - Assert with side-effect: separate
sys.path.pop()fromassertintest_init.py. - Non-standard exception in special method: return
NotImplementedinstead of raisingTypeErrorinReflection.__sub__(). - Unused exception object: add missing
raiseinhkl_soleil-python_api.py.
- Unused local variables:
- Additional cleanup found during CodeQL review:
- Remove redundant outer loop in
test_misc.pytest_axes_to_dict(). - Rename overwritten loop variable
solutionintest_diffract.py. - Remove unnecessary intermediate assignments before
returninhkl_soleil.py,incident.py,misc.py,ops.py, anduser.py(RET504).
- Remove redundant outer loop in
- Review TODO & FIXME markers: remove resolved comments, open new issues for remaining concerns. (:issue:`260`)
Released 2026-04-03.
- Fix docs workflow race condition:
switcher.jsonupdate now pulls with rebase before pushing togh-pages, preventingfetch firstpush failures when a concurrent deploy has already advanced the branch. (:issue:`263`)
- Add
scripts/release.shinteractive release checklist: automatesswitcher.jsonupdate, pre-commit, commit, tag, and GitHub Release steps in the correct order; supports--dry-runto preview all actions without making changes. (:issue:`263`)
Released 2026-04-03.
- Add :func:`~hklpy2.misc.simulator_from_config` to create a simulated diffractometer (no hardware) from a saved configuration file or dict. (:issue:`210`)
- Add
TypedDictsubclasses for structured solver and configuration dicts: :class:`~hklpy2.backends.typing.ReflectionDict`, :class:`~hklpy2.backends.typing.SampleDict`, and :class:`~hklpy2.backends.typing.SolverMetadataDict` inbackends/typing.py; :class:`~hklpy2.typing.ConfigHeaderDict` inhklpy2/typing.py; andHklSolverMetadataDictinhkl_soleil.pyas the pattern for solver-specific metadata extensions. (:issue:`233`) - Consolidate type aliases (
KeyValueMap,NamedFloatDict,Matrix3x3,NUMERIC,AxesDict,AxesArray,AxesList,AxesTuple,AnyAxesType,BlueskyPlanType,INPUT_VECTOR) from :mod:`hklpy2.misc` into :mod:`hklpy2.typing`; backward-compatible re-exports remain in :mod:`hklpy2.misc`. (:issue:`252`) - Export :func:`~hklpy2.misc.get_run_orientation` and
:func:`~hklpy2.misc.list_orientation_runs` at the top-level
hklpy2namespace, consistent with :class:`~hklpy2.misc.ConfigurationRunWrapper`. (:issue:`231`) - Add how-to guide for choosing the default
forward()solution picker (pick_first_solution,pick_closest_solution, or custom). (:issue:`224`) - Publish versioned docs:
mainbranch tolatest/, each tag to<version>/; add version-switcher dropdown to navbar; auto-updateswitcher.jsonon new tags. (:issue:`213`) - Show a banner on dev/pre-release doc pages noting that a stable version is available, with a link to it. (:issue:`213`)
- Fix
diffractometer.configuration = configsetter to delegate to :meth:`~hklpy2.diffract.DiffractometerBase.restore`, applying geometry validation, beam/wavelength restoration, and state clearing consistently with callingrestore()directly. (:issue:`231`) - Fix stale lattice parameters not reaching the solver before
calc_UB()computes the orientation matrix; lattice changes now propagate immediately viaLattice.__setattr__→Samplecallback → solver update, so subsequentforward()/inverse()calls use the correct lattice. (:issue:`240`, :pr:`244`) - Fix
LimitsConstraint.valid()rejecting solver solutions that land just outside a limit boundary due to floating-point arithmetic; increaseENDPOINT_TOLERANCEfrom1e-7to1e-4. (:issue:`242`) - Fix :func:`~hklpy2.misc.simulator_from_config` restoring reflections with
wrong axis values when YAML serialises
realsdict keys alphabetically instead of in physical axis order. (:issue:`243`) - Fix error message bugs: missing f-string prefix in
hkl_soleil.py, typo"must by"→"must be"insample.py, trailing comma inuser.pyset_wavelength()message; standardizeNoForwardSolutionsmessage; deduplicate_headerkey message into a constant; fix capitalization inconsistency. (:issue:`199`) - Sort glossary alphabetically; fix
:real:→:virtual:typo in glossary entry. (:issue:`235`)
- Add
re.escape()to allpytest.raises(match=...)calls that were using raw strings. (:issue:`232`) - Clarify the complementary roles of
standardize_pseudos/standardize_reals(solver/Core layer, returnsAxesDict) vs. the ophyd@pseudo_position_argument/@real_position_argumentdecorators (diffractometer layer, returns namedtuple); remove three redundant pre-normalisation calls indiffract.pywhere the ophyd decorator already handles flexible input. (:issue:`247`) - Fix type annotations:
*realsin :func:`~hklpy2.user.setor` fromAnyAxesTypetoNUMERIC;**kwargsin :func:`~hklpy2.misc.dict_device_factory` fromKeyValueMaptoAny;Matrix3x3from deprecatedtyping.Listto built-inlist. (:issue:`230`) - Remove deprecated
assert_context_result()helper and all 117 call sites; fold error message strings intomatch=re.escape(...)onpytest.raises(); convert bare list param sets topytest.param()withid=. (:issue:`232`) - Backfill workflow no longer patches
conf.pyfrommain; legacy tag builds use their ownconf.pyso the displayed version is correct and no switcher dropdown appears in builds that predate it. (:issue:`213`) - Refactor
scan_extra()into smaller methods: extract input validation, mover construction, metadata assembly, and inner plan helpers; fix latent bug wheredict.update()returnedNonefor run metadata. (:issue:`229`) - Remove resolved TODO comment in
__init__.py;scan_extra()is implemented in :class:`~hklpy2.diffract.DiffractometerBase` and available viafrom hklpy2.user import *. (:issue:`254`)
Released 2026-03-31.
- Add
presetsdict to supply constant-axis values forforward()without moving motors; presets are stored per mode. (:issue:`190`)
- Add
presetGlossary entry; alphabetize Glossary entries. (:issue:`202`) presetssetter now replaces the preset dictionary for the current mode (standard Python assignment semantics) rather than merging into it. Usepresets = {}to clear;clear_presets()is removed. (:issue:`219`)- Document
presetssetter replace behavior, per-mode storage, and effect onforward()solutions. Add how-to guide and Core concepts summary table. (:issue:`200`, :issue:`219`) - Improve Sphinx Index consistency: primary
!termentries now point to the most substantive page for each term rather than the Glossary. (:issue:`202`) - Trim
concepts/diffract.rstto a brief concept overview; move guide and example content toguides/diffract.rst. (:issue:`204`) - Trim
concepts/solvers.rstto a brief concept overview; move how-to content to newguides/solvers.rst; addentry pointGlossary entry. (:issue:`205`) - Use US spelling throughout docs and source. (:issue:`202`)
%wabluesky magic raisesTypeErrorfor diffractometers under numpy 2.x; this is a bluesky upstream bug triggered by numpy 2.0 tighteningndarray.__format__. (:issue:`201`)cahkl()now returns solutions at motor positions that previously yielded no results. (:issue:`193`)calc_UB()now raises a clearValueErrorwith diagnostic hints when libhkl returns a degenerate U matrix, rather than a cryptic downstream error. (:issue:`207`)- Constraints example: rename "Freeze an axis" to "Limited range";
add "Preset (frozen) axes" section; update SPEC
freeze/unfreezecross-references to point to presets. (:issue:`212`) forward()solutions no longer use wrong angle values from orientation reflections when computing constant-axis modes. (:issue:`195`)
- Add
sphinx.ext.extlinksto Sphinx config; define:issue:and:pr:roles pointing to GitHub. (:issue:`203`) - Bump
actions/upload-artifactfrom v6 to v7. (:pr:`194`) - Skip CI unit tests for pull requests that change only documentation.
Released 2026-01-12.
- Support (define, scan) crystallographic zones.
- creator() not connecting with EPICS
- UB computed from 2 reflections should match expected value.
Released 2025-12-02.
- Add Python type annotations to source code.
- Add reference to DeepWiki site.
- Relocate source code from 'hklpy2' to 'src/hklpy2'.
- Transition from databroker to tiled.
Released 2025-11-25.
- 'creator()' and 'diffractometer_class_factory()': replace 'aliases' with '_pseudo' and '_real'.
Released 2025-11-22.
- Resolve inconsistent forward() results.
- WavelengthXray: Synchronize & initialize energy when wavelength changes.
- Add APS ISN diffractometer notebook.
- Lattice: 0.0 and None are different.
- Remove unit tests for tardis diffractometer.
Released 2025-10-10.
- Compute lattice B matrix.
- '@crw_decorator()': Decorator for the ConfigurationRunWrapper
- Allow update of '.core.extras["h2"] = 1.0'
- Energy was not changed initially by 'wavelength.put(new_value)'.
- DiffractometerError raised by 'hklpy2.user.wh()''
- TypeError from 'diffractometer.wh()' and EPICS.
- TypeError when diffractometer was not connected.
- Add advice files for virtual AI chat agents.
- Add and demonstrate SPEC-style pseudoaxes.
- Add inverse transformation to DiffractometerBase.scan_extra() method.
- Add virtual axes.
- Complete 'refineLattice()' for Core and Sample.
- Compute B from sample lattice.
- Control displayed precision of position tuples using 'DIFFRACTOMETER.digits' property.
- Consistent response when no forward solutions are found.
- Engineering units throughout
- Solver defines the units it uses.
- Conversion to/from solver's units.
- Lattice, beam, rotational axes can all have their own units.
- Ensure unit cell edge length units match wavelength units.
- Extend 'creator()' factory for custom real axis specifications.
- Improve code coverage.
- New GHA jobs cancel in in-progress jobs.
- Pick the 'forward()' solution closest to the current angles.
- 'scan_extra' plan now supports one or more extras (similar to bp.scan).
- Simple math for reflections: r1+r2, r1-r2, r1 == r2, ...
- Update table with SPEC comparison
Released 2025-07-21.
- Resolve TypeError raised from auxiliary pseudo position.
- Cancel in-progress GHA jobs when new one is started.
- Remove diffractometer solver_signature component.
Released 2025-07-18.
- Added FAQ document.
- Added 'pick_closest_solution()' as alternative 'forward()' decision function.
- Added 'VirtualPositionerBase' base class.
- Completed 'refineLattice()' method for both Core and Sample classes.
- Utility function 'check_value_in_list()' not needed at package level.
Released 2025-04-16.
- Move project to bluesky organization on GitHub.
- core.add_reflection() should define when wavelength=None
Released 2025-04-14.
- Do not package unit test code.
- Packaging changes in
pyproject.toml. - Unit test changes affecting hklpy2/__init__.py.
Released 2025-04-14.
Initial project development complete.
- Ready for relocation to Bluesky organization on GitHub.
- See :ref:`concepts` for more details about how this works.
- See :ref:`v2_checklist` for progress on what has been planned.
- For those familiar with SPEC, see :ref:`spec_commands_map`.