Releases#
Brief notes describing each release and what’s new.
Project milestones describe future plans.
0.6.0#
Released 2026-04-16.
Breaking Changes#
Rename
creator_from_config()tosimulator_from_config()to clarify that it always produces a simulator with no hardware connections. (issue #363)
New Features#
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)
Maintenance#
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)
Fixes#
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)
Deprecations#
Deprecate
move_zoneandscan_zoneimports fromhklpy2.blocks.zone; usehklpy2.plansinstead. (issue #339)
Maintenance#
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)
0.5.2#
Released 2026-04-15.
patch-up release per standard release procedure
0.5.1#
Released 2026-04-15.
New Features#
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:
hklpy2.userinteractive 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)
Maintenance#
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)
0.5.0#
Released 2026-04-14.
New Features#
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)
Fixes#
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)
Maintenance#
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)
0.4.3#
Released 2026-04-07.
Enhancements#
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)
Maintenance#
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)
0.4.2#
Released 2026-04-06.
New Features#
Add
move_zone()plan (SPECmzequivalent): move diffractometer to a pseudo position in the zone. (issue #273)Export
OrthonormalZoneandmove_zone()from the top-levelhklpy2package. (issue #273)
Fixes#
Fix
removeAllReflections()to clear reflections list and reset wavelength instead of raisingNotImplementedError. (issue #267)Remove unused
INPUT_VECTORandNUMERICre-exports frommisc.py; nothing imported them from there. (issue #267)Fix metadata dict bug in
scan_zone(): thedict(...).update(...)pattern always returnedNone; replaced with unpacking syntax. (issue #273)
Maintenance#
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.
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).
Review TODO & FIXME markers: remove resolved comments, open new issues for remaining concerns. (issue #260)
0.4.1#
Released 2026-04-03.
Fixes#
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)
Maintenance#
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)
0.4.0#
Released 2026-04-03.
New Features#
Add
simulator_from_config()to create a simulated diffractometer (no hardware) from a saved configuration file or dict. (issue #210)
Enhancements#
Add
TypedDictsubclasses for structured solver and configuration dicts:ReflectionDict,SampleDict, andSolverMetadataDictinbackends/typing.py;ConfigHeaderDictinhklpy2/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) fromhklpy2.miscintohklpy2.typing; backward-compatible re-exports remain inhklpy2.misc. (issue #252)Export
get_run_orientation()andlist_orientation_runs()at the top-levelhklpy2namespace, consistent withConfigurationRunWrapper. (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)
Fixes#
Fix
diffractometer.configuration = configsetter to delegate torestore(), 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
simulator_from_config()restoring reflections with wrong axis values when YAML serialisesrealsdict 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)
Maintenance#
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:
*realsinsetor()fromAnyAxesTypetoNUMERIC;**kwargsindict_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 inDiffractometerBaseand available viafrom hklpy2.user import *. (issue #254)
0.3.1#
Released 2026-03-31.
New Features#
Add
presetsdict to supply constant-axis values forforward()without moving motors; presets are stored per mode. (issue #190)
Enhancements#
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)
Fixes#
%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)
Maintenance#
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.
0.3.0#
Released 2026-01-12.
New Features#
Support (define, scan) crystallographic zones.
Fixes#
creator() not connecting with EPICS
Maintenance#
UB computed from 2 reflections should match expected value.
0.2.3#
Released 2025-12-02.
Maintenance#
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.
0.2.2#
Released 2025-11-25.
Maintenance#
‘creator()’ and ‘diffractometer_class_factory()’: replace ‘aliases’ with ‘_pseudo’ and ‘_real’.
0.2.1#
Released 2025-11-22.
Fixes#
Resolve inconsistent forward() results.
WavelengthXray: Synchronize & initialize energy when wavelength changes.
Maintenance#
Add APS ISN diffractometer notebook.
Lattice: 0.0 and None are different.
Remove unit tests for tardis diffractometer.
0.2.0#
Released 2025-10-10.
New Features#
Compute lattice B matrix.
‘@crw_decorator()’: Decorator for the ConfigurationRunWrapper
Fixes#
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.
Maintenance#
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
0.1.5#
Released 2025-07-21.
Fixes#
Resolve TypeError raised from auxiliary pseudo position.
Maintenance#
Cancel in-progress GHA jobs when new one is started.
Remove diffractometer solver_signature component.
0.1.4#
Released 2025-07-18.
New Features#
Added FAQ document.
Added ‘pick_closest_solution()’ as alternative ‘forward()’ decision function.
Added ‘VirtualPositionerBase’ base class.
Maintenance#
Completed ‘refineLattice()’ method for both Core and Sample classes.
Utility function ‘check_value_in_list()’ not needed at package level.
0.1.3#
Released 2025-04-16.
Notice#
- Move project to bluesky organization on GitHub.
Fixes#
core.add_reflection() should define when wavelength=None
0.1.2#
Released 2025-04-14.
Fixes#
Do not package unit test code.
Packaging changes in
pyproject.toml.Unit test changes affecting hklpy2/__init__.py.
0.1.0#
Released 2025-04-14.
Initial project development complete.
Notice#
Ready for relocation to Bluesky organization on GitHub.
See Concepts for more details about how this works.
See Feature Checklist for v2 for progress on what has been planned.
For those familiar with SPEC, see SPEC commands in hklpy2.