From 5fb7a893cc39f6232b6950df790c0d8fd61ca59f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 15 Oct 2026 10:27:57 -0400 Subject: [PATCH 1/6] chore: replace deprecated functions --- news/fix-structure-deprecations.rst | 23 ++++++++++++++++++++ src/diffpy/srfit/structure/objcrystparset.py | 8 +++---- src/diffpy/srfit/structure/sgconstraints.py | 10 ++++----- tests/test_objcrystparset.py | 2 +- tests/test_pdfcontribution.py | 4 ++-- tests/test_sgconstraints.py | 4 ++-- 6 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 news/fix-structure-deprecations.rst diff --git a/news/fix-structure-deprecations.rst b/news/fix-structure-deprecations.rst new file mode 100644 index 00000000..086636ef --- /dev/null +++ b/news/fix-structure-deprecations.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* Use ``get_space_group``, ``position_formulas``, and ``u_formulas`` in place of the deprecated ``diffpy.structure`` functions ``GetSpaceGroup``, ``positionFormulas``, and ``UFormulas`` to silence deprecation warnings. + +**Security:** + +* diff --git a/src/diffpy/srfit/structure/objcrystparset.py b/src/diffpy/srfit/structure/objcrystparset.py index fc08b493..02a821c2 100644 --- a/src/diffpy/srfit/structure/objcrystparset.py +++ b/src/diffpy/srfit/structure/objcrystparset.py @@ -1911,7 +1911,7 @@ def _create_space_group(sgobjcryst): """ import copy - from diffpy.structure.spacegroups import GetSpaceGroup, SymOp + from diffpy.structure.spacegroups import SymOp, get_space_group name = sgobjcryst.GetName() extnstr = ":%s" % sgobjcryst.GetExtension() @@ -1919,9 +1919,9 @@ def _create_space_group(sgobjcryst): name = name[: -len(extnstr)] # Get whatever spacegroup we can get by name. This will set the proper - # crystal system. Creating a copy of the singleton from GetSpaceGroup, - # as this function messes with sg.symop_list. - sg = copy.copy(GetSpaceGroup(name)) + # crystal system. Creating a copy of the singleton from + # get_space_group, as this function messes with sg.symop_list. + sg = copy.copy(get_space_group(name)) # Replace the symmetry operations to guarantee that we get it right. symops = sgobjcryst.GetSymmetryOperations() diff --git a/src/diffpy/srfit/structure/sgconstraints.py b/src/diffpy/srfit/structure/sgconstraints.py index 22d57c8b..4f956a5a 100644 --- a/src/diffpy/srfit/structure/sgconstraints.py +++ b/src/diffpy/srfit/structure/sgconstraints.py @@ -112,11 +112,11 @@ def constrain_as_space_group( b and c are constrained to a, and alpha, beta and gamma are fixed to 90. """ - from diffpy.structure.spacegroups import GetSpaceGroup, SpaceGroup + from diffpy.structure.spacegroups import SpaceGroup, get_space_group sg = spacegroup if not isinstance(spacegroup, SpaceGroup): - sg = GetSpaceGroup(spacegroup) + sg = get_space_group(spacegroup) sgp = _constrain_as_space_group( phase, sg, @@ -309,7 +309,7 @@ def __init__( A BaseStructure object to be constrained. sg The space group number or symbol (compatible with - diffpy.structure.spacegroups.GetSpaceGroup. + diffpy.structure.spacegroups.get_space_group. sgoffset Optional offset for sg origin. scatterers @@ -533,7 +533,7 @@ def _constrain_xyzs(self, positions): self._xyzpars.addParameter(newpar) # Constrain non-free xyz parameters - fpos = g.positionFormulas(xyznames) + fpos = g.position_formulas(xyznames) for idx, tmp in enumerate(zip(scatterers, fpos)): scatterer, fp = tmp @@ -634,7 +634,7 @@ def _constrain_adps(self, positions): isosymbol, isoname, params=self._parameters ) - fadp = g.UFormulas(adpnames) + fadp = g.u_formulas(adpnames) # Constrain dependent anisotropics. We use the fact that an # anisotropic cannot be dependent on an isotropic. diff --git a/tests/test_objcrystparset.py b/tests/test_objcrystparset.py index 53fd00b2..0bc2005f 100644 --- a/tests/test_objcrystparset.py +++ b/tests/test_objcrystparset.py @@ -723,7 +723,7 @@ def xtestCreateSpaceGroup(self): shn = smbls.hermann_mauguin() short_name = shn.replace(" ", "") if spacegroups.IsSpaceGroupIdentifier(short_name): - sg = spacegroups.GetSpaceGroup(shn) + sg = spacegroups.get_space_group(shn) sgnew = self.getObjCrystParSetSpaceGroup(sg) # print("dbsg: " + repr(self.sgsEquivalent(sg, sgnew))) assert self.sgsEquivalent(sg, sgnew) diff --git a/tests/test_pdfcontribution.py b/tests/test_pdfcontribution.py index 69642404..509d2b8b 100644 --- a/tests/test_pdfcontribution.py +++ b/tests/test_pdfcontribution.py @@ -124,7 +124,7 @@ def test_savetxt(diffpy_srreal_available, datafile): def test_pickling(diffpy_srreal_available, datafile): "validate PDFContribution.residual() after pickling." - from diffpy.structure import loadStructure + from diffpy.structure import load_structure if not diffpy_srreal_available: pytest.skip("diffpy.srreal package not available") @@ -133,7 +133,7 @@ def test_pickling(diffpy_srreal_available, datafile): pc.loadData(datafile("ni-q27r100-neutron.gr")) ciffile = datafile("ni.cif") cif_path = str(ciffile) - ni = loadStructure(cif_path) + ni = load_structure(cif_path) ni.Uisoequiv = 0.003 pc.addStructure("ni", ni) pc.setCalculationRange(0, 10) diff --git a/tests/test_sgconstraints.py b/tests/test_sgconstraints.py index 56498ff1..8789228b 100644 --- a/tests/test_sgconstraints.py +++ b/tests/test_sgconstraints.py @@ -187,12 +187,12 @@ def test_constrain_as_space_group_args(pyobjcryst_available, datafile): from diffpy.srfit.structure.diffpyparset import DiffpyStructureParSet from diffpy.srfit.structure.sgconstraints import constrain_as_space_group - from diffpy.structure.spacegroups import GetSpaceGroup + from diffpy.structure.spacegroups import get_space_group stru = makeLaMnO3_P1(datafile) parset = DiffpyStructureParSet("LaMnO3", stru) sgpars = constrain_as_space_group(parset, "P b n m") - sg = GetSpaceGroup("P b n m") + sg = get_space_group("P b n m") parset2 = DiffpyStructureParSet("LMO", makeLaMnO3_P1(datafile)) sgpars2 = constrain_as_space_group(parset2, sg) list(sgpars) From fc89bd7ff0348a0611701182b70b59a087e2e9ef Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 15 Oct 2026 10:57:52 -0400 Subject: [PATCH 2/6] replace deprecated function in test --- tests/test_pdfgenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_pdfgenerator.py b/tests/test_pdfgenerator.py index b1bd8ad7..cabbe6e2 100644 --- a/tests/test_pdfgenerator.py +++ b/tests/test_pdfgenerator.py @@ -46,7 +46,7 @@ def testGenerator(diffpy_srreal_available, datafile): calc = gen._calc # Test parameters - for par in gen.iterPars(recurse=False): + for par in gen.iterate_over_parameters(recurse=False): pname = par.name defval = calc._getDoubleAttr(pname) assert defval == par.get_value() From 58c6781a1273105d69d02ffd394a909b7337ed14 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 15 Oct 2026 11:25:16 -0400 Subject: [PATCH 3/6] fix deprecated functions in examples and add tests for interface --- docs/examples/coreshellnp.py | 8 ++-- docs/examples/crystalpdfall.py | 6 +-- docs/examples/crystalpdfobjcryst.py | 4 +- docs/examples/crystalpdftwodata.py | 4 +- docs/examples/crystalpdftwophase.py | 6 +-- docs/examples/gaussianrecipe.py | 2 +- docs/examples/nppdfcrystal.py | 8 ++-- docs/examples/nppdfsas.py | 4 +- docs/examples/simplepdftwophase.py | 6 +-- docs/examples/threedoublepeaks.py | 2 +- news/fix-structure-deprecations.rst | 2 + src/diffpy/srfit/interface/interface.py | 8 ++-- tests/test_interface.py | 58 +++++++++++++++++++++++++ 13 files changed, 89 insertions(+), 29 deletions(-) create mode 100644 tests/test_interface.py diff --git a/docs/examples/coreshellnp.py b/docs/examples/coreshellnp.py index 2f4353e9..b175ade3 100644 --- a/docs/examples/coreshellnp.py +++ b/docs/examples/coreshellnp.py @@ -22,7 +22,7 @@ from pathlib import Path -from pyobjcryst import loadCrystal +from pyobjcryst.crystal import create_crystal_from_cif from scipy.optimize import leastsq from diffpy.srfit.fitbase import ( @@ -94,7 +94,7 @@ def makeRecipe(stru1, stru2, datname): # diameter to twice the shell radius. recipe.add_variable(contribution.radius, 15) recipe.add_variable(contribution.thickness, 11) - recipe.add_constraint(contribution.psize, "2 * radius") + recipe.add_constraint(contribution.particle_diameter, "2 * radius") # Configure the fit variables # Start by configuring the scale factor and resolution factors. @@ -152,8 +152,8 @@ def main(): data = Path(__file__).parent / "data/CdS_ZnS_nano.gr" # Make the recipe - stru1 = loadCrystal(cdsciffile) - stru2 = loadCrystal(znsciffile) + stru1 = create_crystal_from_cif(str(cdsciffile)) + stru2 = create_crystal_from_cif(str(znsciffile)) recipe = makeRecipe(stru1, stru2, data) from diffpy.srfit.fitbase.fithook import PlotFitHook diff --git a/docs/examples/crystalpdfall.py b/docs/examples/crystalpdfall.py index e851b050..178e1d33 100644 --- a/docs/examples/crystalpdfall.py +++ b/docs/examples/crystalpdfall.py @@ -21,7 +21,7 @@ from pathlib import Path from gaussianrecipe import scipyOptimize -from pyobjcryst import loadCrystal +from pyobjcryst.crystal import create_crystal_from_cif from diffpy.srfit.fitbase import ( FitContribution, @@ -67,12 +67,12 @@ def makeRecipe( # The ProfileGenerators # We create one for each phase and share the phases. xgenerator_ni = PDFGenerator("xG_ni") - stru = loadCrystal(ciffile_ni) + stru = create_crystal_from_cif(str(ciffile_ni)) xgenerator_ni.setStructure(stru) phase_ni = xgenerator_ni.phase xgenerator_si = PDFGenerator("xG_si") - stru = loadCrystal(ciffile_si) + stru = create_crystal_from_cif(str(ciffile_si)) xgenerator_si.setStructure(stru) phase_si = xgenerator_si.phase diff --git a/docs/examples/crystalpdfobjcryst.py b/docs/examples/crystalpdfobjcryst.py index 8db94287..0896a6dd 100644 --- a/docs/examples/crystalpdfobjcryst.py +++ b/docs/examples/crystalpdfobjcryst.py @@ -22,7 +22,7 @@ from pathlib import Path from gaussianrecipe import scipyOptimize -from pyobjcryst import loadCrystal +from pyobjcryst.crystal import create_crystal_from_cif from diffpy.srfit.fitbase import ( FitContribution, @@ -56,7 +56,7 @@ def makeRecipe(ciffile, datname): # create a Crystal object. That object is passed to the PDFGenerator as in # the previous example. generator = PDFGenerator("G") - stru = loadCrystal(ciffile) + stru = create_crystal_from_cif(str(ciffile)) generator.setStructure(stru) generator.setQmax(40.0) diff --git a/docs/examples/crystalpdftwodata.py b/docs/examples/crystalpdftwodata.py index cb6b3091..0eb90375 100644 --- a/docs/examples/crystalpdftwodata.py +++ b/docs/examples/crystalpdftwodata.py @@ -23,7 +23,7 @@ from pathlib import Path from gaussianrecipe import scipyOptimize -from pyobjcryst import loadCrystal +from pyobjcryst.crystal import create_crystal_from_cif from diffpy.srfit.fitbase import ( FitContribution, @@ -59,7 +59,7 @@ def makeRecipe(ciffile, xdatname, ndatname): # The ProfileGenerators # We need one of these for the x-ray data. xgenerator = PDFGenerator("G") - stru = loadCrystal(ciffile) + stru = create_crystal_from_cif(str(ciffile)) xgenerator.setStructure(stru) # And we need one for the neutron data. We want to refine the same diff --git a/docs/examples/crystalpdftwophase.py b/docs/examples/crystalpdftwophase.py index af6d1df7..161bbf65 100644 --- a/docs/examples/crystalpdftwophase.py +++ b/docs/examples/crystalpdftwophase.py @@ -23,7 +23,7 @@ from pathlib import Path from gaussianrecipe import scipyOptimize -from pyobjcryst import loadCrystal +from pyobjcryst.crystal import create_crystal_from_cif from diffpy.srfit.fitbase import ( FitContribution, @@ -61,11 +61,11 @@ def makeRecipe(niciffile, siciffile, datname): # The generator for the nickel phase. We call it "G_ni" and will use this # name later when we set the fitting equation in the FitContribution. generator_ni = PDFGenerator("G_ni") - stru = loadCrystal(niciffile) + stru = create_crystal_from_cif(str(niciffile)) generator_ni.setStructure(stru) # The generator for the silicon phase. We call it "G_si". generator_si = PDFGenerator("G_si") - stru = loadCrystal(siciffile) + stru = create_crystal_from_cif(str(siciffile)) generator_si.setStructure(stru) # The FitContribution diff --git a/docs/examples/gaussianrecipe.py b/docs/examples/gaussianrecipe.py index 039003ae..97848fba 100644 --- a/docs/examples/gaussianrecipe.py +++ b/docs/examples/gaussianrecipe.py @@ -172,7 +172,7 @@ def scipyOptimize(recipe): # scipy. We simply have to give it the function to minimize # (recipe.residual) and the starting values of the Variables # (recipe.get_values()). - from scipy.optimize.minpack import leastsq + from scipy.optimize import leastsq print("Fit using scipy's LM optimizer") leastsq(recipe.residual, recipe.get_values()) diff --git a/docs/examples/nppdfcrystal.py b/docs/examples/nppdfcrystal.py index ec3adc37..0911754d 100644 --- a/docs/examples/nppdfcrystal.py +++ b/docs/examples/nppdfcrystal.py @@ -27,7 +27,7 @@ import matplotlib.pyplot as plt from gaussianrecipe import scipyOptimize -from pyobjcryst import loadCrystal +from pyobjcryst.crystal import create_crystal_from_cif from diffpy.srfit.fitbase import ( FitContribution, @@ -53,7 +53,7 @@ def makeRecipe(ciffile, grdata): pdfgenerator = PDFGenerator("G") pdfgenerator.setQmax(30.0) - stru = loadCrystal(ciffile) + stru = create_crystal_from_cif(str(ciffile)) pdfgenerator.setStructure(stru) pdfcontribution.add_profile_generator(pdfgenerator) @@ -66,7 +66,7 @@ def makeRecipe(ciffile, grdata): pdfcontribution.set_equation("f * G") # Now make the recipe. Make sure we fit the characteristic function shape - # parameters, in this case 'psize', which is the diameter of the particle. + # parameters, in this case 'particle_diameter'. recipe = FitRecipe() recipe.add_contribution(pdfcontribution) @@ -74,7 +74,7 @@ def makeRecipe(ciffile, grdata): for par in phase.sgpars: recipe.add_variable(par) - recipe.add_variable(pdfcontribution.psize, 20) + recipe.add_variable(pdfcontribution.particle_diameter, 20) recipe.add_variable(pdfgenerator.scale, 1) recipe.add_variable(pdfgenerator.delta2, 0) recipe.B11_0 = 0.1 diff --git a/docs/examples/nppdfsas.py b/docs/examples/nppdfsas.py index 91983bdf..ea049ec7 100644 --- a/docs/examples/nppdfsas.py +++ b/docs/examples/nppdfsas.py @@ -26,7 +26,7 @@ import matplotlib.pyplot as plt from gaussianrecipe import scipyOptimize -from pyobjcryst import loadCrystal +from pyobjcryst.crystal import create_crystal_from_cif from diffpy.srfit.fitbase import ( FitContribution, @@ -58,7 +58,7 @@ def makeRecipe(ciffile, grdata, iqdata): pdfgenerator = PDFGenerator("G") pdfgenerator.setQmax(30.0) - stru = loadCrystal(ciffile) + stru = create_crystal_from_cif(str(ciffile)) pdfgenerator.setStructure(stru) pdfcontribution.add_profile_generator(pdfgenerator) pdfcontribution.set_residual_equation("resv") diff --git a/docs/examples/simplepdftwophase.py b/docs/examples/simplepdftwophase.py index 520b734c..9889b44f 100644 --- a/docs/examples/simplepdftwophase.py +++ b/docs/examples/simplepdftwophase.py @@ -17,7 +17,7 @@ from pathlib import Path from gaussianrecipe import scipyOptimize -from pyobjcryst import loadCrystal +from pyobjcryst.crystal import create_crystal_from_cif from diffpy.srfit.fitbase import FitRecipe, FitResults from diffpy.srfit.pdf import PDFContribution @@ -33,10 +33,10 @@ def makeRecipe(niciffile, siciffile, datname): contribution.loadData(datname) contribution.set_calculation_range(xmax=20) - stru = loadCrystal(niciffile) + stru = create_crystal_from_cif(str(niciffile)) contribution.addStructure("ni", stru) - stru = loadCrystal(siciffile) + stru = create_crystal_from_cif(str(siciffile)) contribution.addStructure("si", stru) # Make the FitRecipe and add the FitContribution. diff --git a/docs/examples/threedoublepeaks.py b/docs/examples/threedoublepeaks.py index a6de86a8..0b013ead 100644 --- a/docs/examples/threedoublepeaks.py +++ b/docs/examples/threedoublepeaks.py @@ -184,7 +184,7 @@ def scipyOptimize(recipe): # scipy. We simply have to give it the function to minimize # (recipe.residual) and the starting values of the Variables # (recipe.get_values()). - from scipy.optimize.minpack import leastsq + from scipy.optimize import leastsq print("Fit using scipy's LM optimizer") leastsq(recipe.residual, recipe.get_values()) diff --git a/news/fix-structure-deprecations.rst b/news/fix-structure-deprecations.rst index 086636ef..5cbb747e 100644 --- a/news/fix-structure-deprecations.rst +++ b/news/fix-structure-deprecations.rst @@ -17,6 +17,8 @@ **Fixed:** * Use ``get_space_group``, ``position_formulas``, and ``u_formulas`` in place of the deprecated ``diffpy.structure`` functions ``GetSpaceGroup``, ``positionFormulas``, and ``UFormulas`` to silence deprecation warnings. +* Use ``add_constraint`` and ``add_soft_bounds`` in the ``*=`` and ``%=`` operators of ``RecipeOrganizerInterface`` so they no longer raise deprecation warnings for ``constrain`` and ``restrain``. +* Use ``pyobjcryst.crystal.create_crystal_from_cif``, ``scipy.optimize.leastsq``, and the ``particle_diameter`` argument of ``spherical_particle`` in the examples in place of deprecated or renamed APIs. **Security:** diff --git a/src/diffpy/srfit/interface/interface.py b/src/diffpy/srfit/interface/interface.py index cf0bcdce..7d172a46 100644 --- a/src/diffpy/srfit/interface/interface.py +++ b/src/diffpy/srfit/interface/interface.py @@ -72,14 +72,14 @@ def __imul__(self, args): Parameters ---------- args : tuple - The arguments to pass to `constrain`. + The arguments to pass to `add_constraint`. Returns ------- RecipeOrganizerInterface Return self after applying the constraint. """ - _applyargs(args, self.constrain) + _applyargs(args, self.add_constraint) return self def __imod__(self, args): @@ -91,14 +91,14 @@ def __imod__(self, args): Parameters ---------- args : tuple - The arguments to pass to `restrain`. + The arguments to pass to `add_soft_bounds`. Returns ------- RecipeOrganizerInterface Return self after applying the restraint. """ - _applyargs(args, self.restrain) + _applyargs(args, self.add_soft_bounds) return self def __iadd__(self, args): diff --git a/tests/test_interface.py b/tests/test_interface.py new file mode 100644 index 00000000..12f9b830 --- /dev/null +++ b/tests/test_interface.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +############################################################################## +# +# diffpy.srfit by DANSE Diffraction group +# Simon J. L. Billinge +# (c) 2026 The Trustees of Columbia University +# in the City of New York. All rights reserved. +# +# File coded by: Caden Myers +# +# See AUTHORS.txt for a list of people who contributed. +# See LICENSE_DANSE.txt for license information. +# +############################################################################## +"""Tests for the interface module.""" + +from diffpy.srfit.fitbase import FitRecipe + + +def _make_recipe_with_variables(): + """Return a recipe with the variables p1 = 1 and p2 = 2.""" + recipe = FitRecipe("recipe") + p1 = recipe.create_new_variable("p1", 1) + p2 = recipe.create_new_variable("p2", 2) + return recipe, p1, p2 + + +# Test that "*=" constrains a Parameter to an equation. +# C1: p1 is constrained to "2*p2" with "*=", and p2 is then set to 3. +# Expected: p1 is constrained and its value is 6, without a deprecation +# warning. +def test_constrain_operator(): + recipe, p1, p2 = _make_recipe_with_variables() + recipe *= "p1", "2*p2" + p2.set_value(3) + recipe._constraints[p1].update() + assert recipe.is_constrained(p1) + actual_p1_value = p1.get_value() + expected_p1_value = 6 + assert actual_p1_value == expected_p1_value + + +# Test that "%=" restrains an equation between soft bounds. +# C1: "p1+p2" is restrained between 0 and 10 with "%=", and p2 is then set +# to 10. +# Expected: The recipe has one restraint with a penalty of 1, without a +# deprecation warning. +def test_restrain_operator(): + recipe, _, p2 = _make_recipe_with_variables() + recipe %= "p1+p2", 0, 10 + p2.set_value(10) + actual_number_of_restraints = len(recipe._restraints) + expected_number_of_restraints = 1 + assert actual_number_of_restraints == expected_number_of_restraints + (restraint,) = recipe._restraints + actual_penalty = restraint.penalty() + expected_penalty = 1 + assert actual_penalty == expected_penalty From 6513f14b64c8ed8a9bb9b6a77466ad14d9200ec9 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 15 Oct 2026 11:27:50 -0400 Subject: [PATCH 4/6] fix file header --- tests/test_interface.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/test_interface.py b/tests/test_interface.py index 12f9b830..ecad7eaa 100644 --- a/tests/test_interface.py +++ b/tests/test_interface.py @@ -1,15 +1,14 @@ #!/usr/bin/env python ############################################################################## # -# diffpy.srfit by DANSE Diffraction group -# Simon J. L. Billinge -# (c) 2026 The Trustees of Columbia University -# in the City of New York. All rights reserved. +# (c) 2026-present The DiffPy Team. All rights reserved. # -# File coded by: Caden Myers +# File coded by: Caden Myers # -# See AUTHORS.txt for a list of people who contributed. -# See LICENSE_DANSE.txt for license information. +# See GitHub contributions for a more detailed list of contributors. +# https://github.com/diffpy/diffpy.srfit/graphs/contributors +# +# See LICENSE.rst for license information. # ############################################################################## """Tests for the interface module.""" @@ -27,8 +26,7 @@ def _make_recipe_with_variables(): # Test that "*=" constrains a Parameter to an equation. # C1: p1 is constrained to "2*p2" with "*=", and p2 is then set to 3. -# Expected: p1 is constrained and its value is 6, without a deprecation -# warning. +# Expected: p1 is constrained and its value is 6. def test_constrain_operator(): recipe, p1, p2 = _make_recipe_with_variables() recipe *= "p1", "2*p2" @@ -43,8 +41,7 @@ def test_constrain_operator(): # Test that "%=" restrains an equation between soft bounds. # C1: "p1+p2" is restrained between 0 and 10 with "%=", and p2 is then set # to 10. -# Expected: The recipe has one restraint with a penalty of 1, without a -# deprecation warning. +# Expected: The recipe has one restraint with a penalty of 1. def test_restrain_operator(): recipe, _, p2 = _make_recipe_with_variables() recipe %= "p1+p2", 0, 10 From ed0fd62357c9dcd24dee45eca652fb2e695d0dbd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 15 Oct 2026 11:30:06 -0400 Subject: [PATCH 5/6] trigger ci From b35b24dec1f3477b690cdb21d8151cad832cdc92 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 15 Oct 2026 12:21:23 -0400 Subject: [PATCH 6/6] doc: add short hand operators to docs --- docs/source/api/diffpy.srfit.interface.rst | 1 + news/fix-structure-deprecations.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/api/diffpy.srfit.interface.rst b/docs/source/api/diffpy.srfit.interface.rst index 92497fea..302e98e1 100644 --- a/docs/source/api/diffpy.srfit.interface.rst +++ b/docs/source/api/diffpy.srfit.interface.rst @@ -17,4 +17,5 @@ diffpy.srfit.interface.interface module .. automodule:: diffpy.srfit.interface.interface :members: :undoc-members: + :special-members: __lshift__, __imul__, __imod__, __iadd__, __ior__ :show-inheritance: diff --git a/news/fix-structure-deprecations.rst b/news/fix-structure-deprecations.rst index 5cbb747e..ba4ee167 100644 --- a/news/fix-structure-deprecations.rst +++ b/news/fix-structure-deprecations.rst @@ -1,6 +1,6 @@ **Added:** -* +* Document the ``*=``, ``%=``, ``+=``, ``|=``, and ``<<`` shorthand operators in the ``diffpy.srfit.interface`` API reference. **Changed:**