From 0f3293fe2713db001e6ce6608c0769df7b21a118 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 23 Sep 2025 14:04:29 -0400 Subject: [PATCH 01/21] move examples under pdf dir --- docs/examples/{ => pdf}/ch03NiModelling/data/Ni.cif | 0 docs/examples/{ => pdf}/ch03NiModelling/data/Ni.gr | 0 docs/examples/{ => pdf}/ch03NiModelling/data/Pt-nanoparticles.gr | 0 docs/examples/{ => pdf}/ch03NiModelling/data/Pt.cif | 0 .../ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb | 0 .../{ => pdf}/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb | 0 .../{ => pdf}/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py | 0 .../solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb | 0 .../{ => pdf}/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py | 0 .../ch03NiModelling/solutions/diffpy-cmi/helper_functions.py | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/Ni_Fm-3m.cif | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/Si_Fd-3m.cif | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/iq/ni.iq | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/iq/ph.txt | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/iq/si.iq | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/iq/sini.iq | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/ni.gr | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/si.gr | 0 docs/examples/{ => pdf}/ch05Fit2Phase/data/sini.gr | 0 .../{ => pdf}/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py | 0 .../{ => pdf}/ch06RefineCrystalStructureGen/data/BaZn2As2.cif | 0 .../data/BaZn2As2_K-Mn-doped_300K.gr | 0 .../solutions/diffpy-cmi/fitCrystalGen.py | 0 .../solutions/pdfgui/BaZn2As2_mod.cif | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_150K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_156K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_162K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_168K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_174K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_180K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_186K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_192K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_198K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_204K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_210K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_216K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_222K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_228K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_234K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_240K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_246K.gr | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_orthorhombic.cif | 0 .../ch07StructuralPhaseTransitions/data/SrFe2As2_tetragonal.cif | 0 .../solutions/diffpy-cmi/fitTSeries.py | 0 docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-1.gr | 0 docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-2.gr | 0 docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-3.gr | 0 docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-4.gr | 0 docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-Wurtzite.cif | 0 docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-Zincblende.cif | 0 docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-bulk.gr | 0 .../{ => pdf}/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py | 0 docs/examples/{ => pdf}/ch11ClusterXYZ/data/CdSe.gr | 0 docs/examples/{ => pdf}/ch11ClusterXYZ/data/CdSe.xyz | 0 .../{ => pdf}/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py | 0 55 files changed, 0 insertions(+), 0 deletions(-) rename docs/examples/{ => pdf}/ch03NiModelling/data/Ni.cif (100%) rename docs/examples/{ => pdf}/ch03NiModelling/data/Ni.gr (100%) rename docs/examples/{ => pdf}/ch03NiModelling/data/Pt-nanoparticles.gr (100%) rename docs/examples/{ => pdf}/ch03NiModelling/data/Pt.cif (100%) rename docs/examples/{ => pdf}/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb (100%) rename docs/examples/{ => pdf}/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb (100%) rename docs/examples/{ => pdf}/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py (100%) rename docs/examples/{ => pdf}/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb (100%) rename docs/examples/{ => pdf}/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py (100%) rename docs/examples/{ => pdf}/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/Ni_Fm-3m.cif (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/Si_Fd-3m.cif (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/iq/ni.iq (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/iq/ph.txt (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/iq/si.iq (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/iq/sini.iq (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/ni.gr (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/si.gr (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/data/sini.gr (100%) rename docs/examples/{ => pdf}/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py (100%) rename docs/examples/{ => pdf}/ch06RefineCrystalStructureGen/data/BaZn2As2.cif (100%) rename docs/examples/{ => pdf}/ch06RefineCrystalStructureGen/data/BaZn2As2_K-Mn-doped_300K.gr (100%) rename docs/examples/{ => pdf}/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py (100%) rename docs/examples/{ => pdf}/ch06RefineCrystalStructureGen/solutions/pdfgui/BaZn2As2_mod.cif (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_150K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_156K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_162K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_168K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_174K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_180K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_186K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_192K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_198K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_204K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_210K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_216K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_222K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_228K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_234K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_240K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_246K.gr (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_orthorhombic.cif (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/data/SrFe2As2_tetragonal.cif (100%) rename docs/examples/{ => pdf}/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py (100%) rename docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-1.gr (100%) rename docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-2.gr (100%) rename docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-3.gr (100%) rename docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-4.gr (100%) rename docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-Wurtzite.cif (100%) rename docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-Zincblende.cif (100%) rename docs/examples/{ => pdf}/ch08NPRefinement/data/CdSe-bulk.gr (100%) rename docs/examples/{ => pdf}/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py (100%) rename docs/examples/{ => pdf}/ch11ClusterXYZ/data/CdSe.gr (100%) rename docs/examples/{ => pdf}/ch11ClusterXYZ/data/CdSe.xyz (100%) rename docs/examples/{ => pdf}/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py (100%) diff --git a/docs/examples/ch03NiModelling/data/Ni.cif b/docs/examples/pdf/ch03NiModelling/data/Ni.cif similarity index 100% rename from docs/examples/ch03NiModelling/data/Ni.cif rename to docs/examples/pdf/ch03NiModelling/data/Ni.cif diff --git a/docs/examples/ch03NiModelling/data/Ni.gr b/docs/examples/pdf/ch03NiModelling/data/Ni.gr similarity index 100% rename from docs/examples/ch03NiModelling/data/Ni.gr rename to docs/examples/pdf/ch03NiModelling/data/Ni.gr diff --git a/docs/examples/ch03NiModelling/data/Pt-nanoparticles.gr b/docs/examples/pdf/ch03NiModelling/data/Pt-nanoparticles.gr similarity index 100% rename from docs/examples/ch03NiModelling/data/Pt-nanoparticles.gr rename to docs/examples/pdf/ch03NiModelling/data/Pt-nanoparticles.gr diff --git a/docs/examples/ch03NiModelling/data/Pt.cif b/docs/examples/pdf/ch03NiModelling/data/Pt.cif similarity index 100% rename from docs/examples/ch03NiModelling/data/Pt.cif rename to docs/examples/pdf/ch03NiModelling/data/Pt.cif diff --git a/docs/examples/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb b/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb similarity index 100% rename from docs/examples/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb rename to docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitBulkNi.ipynb diff --git a/docs/examples/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb b/docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb similarity index 100% rename from docs/examples/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb rename to docs/examples/pdf/ch03NiModelling/exercises/diffpy-cmi/fitNPPt.ipynb diff --git a/docs/examples/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py similarity index 100% rename from docs/examples/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py rename to docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi.py diff --git a/docs/examples/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb similarity index 100% rename from docs/examples/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb rename to docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitBulkNi_NPPt_soln2.ipynb diff --git a/docs/examples/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py similarity index 100% rename from docs/examples/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py rename to docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/fitNPPt.py diff --git a/docs/examples/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py b/docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py similarity index 100% rename from docs/examples/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py rename to docs/examples/pdf/ch03NiModelling/solutions/diffpy-cmi/helper_functions.py diff --git a/docs/examples/ch05Fit2Phase/data/Ni_Fm-3m.cif b/docs/examples/pdf/ch05Fit2Phase/data/Ni_Fm-3m.cif similarity index 100% rename from docs/examples/ch05Fit2Phase/data/Ni_Fm-3m.cif rename to docs/examples/pdf/ch05Fit2Phase/data/Ni_Fm-3m.cif diff --git a/docs/examples/ch05Fit2Phase/data/Si_Fd-3m.cif b/docs/examples/pdf/ch05Fit2Phase/data/Si_Fd-3m.cif similarity index 100% rename from docs/examples/ch05Fit2Phase/data/Si_Fd-3m.cif rename to docs/examples/pdf/ch05Fit2Phase/data/Si_Fd-3m.cif diff --git a/docs/examples/ch05Fit2Phase/data/iq/ni.iq b/docs/examples/pdf/ch05Fit2Phase/data/iq/ni.iq similarity index 100% rename from docs/examples/ch05Fit2Phase/data/iq/ni.iq rename to docs/examples/pdf/ch05Fit2Phase/data/iq/ni.iq diff --git a/docs/examples/ch05Fit2Phase/data/iq/ph.txt b/docs/examples/pdf/ch05Fit2Phase/data/iq/ph.txt similarity index 100% rename from docs/examples/ch05Fit2Phase/data/iq/ph.txt rename to docs/examples/pdf/ch05Fit2Phase/data/iq/ph.txt diff --git a/docs/examples/ch05Fit2Phase/data/iq/si.iq b/docs/examples/pdf/ch05Fit2Phase/data/iq/si.iq similarity index 100% rename from docs/examples/ch05Fit2Phase/data/iq/si.iq rename to docs/examples/pdf/ch05Fit2Phase/data/iq/si.iq diff --git a/docs/examples/ch05Fit2Phase/data/iq/sini.iq b/docs/examples/pdf/ch05Fit2Phase/data/iq/sini.iq similarity index 100% rename from docs/examples/ch05Fit2Phase/data/iq/sini.iq rename to docs/examples/pdf/ch05Fit2Phase/data/iq/sini.iq diff --git a/docs/examples/ch05Fit2Phase/data/ni.gr b/docs/examples/pdf/ch05Fit2Phase/data/ni.gr similarity index 100% rename from docs/examples/ch05Fit2Phase/data/ni.gr rename to docs/examples/pdf/ch05Fit2Phase/data/ni.gr diff --git a/docs/examples/ch05Fit2Phase/data/si.gr b/docs/examples/pdf/ch05Fit2Phase/data/si.gr similarity index 100% rename from docs/examples/ch05Fit2Phase/data/si.gr rename to docs/examples/pdf/ch05Fit2Phase/data/si.gr diff --git a/docs/examples/ch05Fit2Phase/data/sini.gr b/docs/examples/pdf/ch05Fit2Phase/data/sini.gr similarity index 100% rename from docs/examples/ch05Fit2Phase/data/sini.gr rename to docs/examples/pdf/ch05Fit2Phase/data/sini.gr diff --git a/docs/examples/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py b/docs/examples/pdf/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py similarity index 100% rename from docs/examples/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py rename to docs/examples/pdf/ch05Fit2Phase/solutions/diffpy-cmi/fit2P.py diff --git a/docs/examples/ch06RefineCrystalStructureGen/data/BaZn2As2.cif b/docs/examples/pdf/ch06RefineCrystalStructureGen/data/BaZn2As2.cif similarity index 100% rename from docs/examples/ch06RefineCrystalStructureGen/data/BaZn2As2.cif rename to docs/examples/pdf/ch06RefineCrystalStructureGen/data/BaZn2As2.cif diff --git a/docs/examples/ch06RefineCrystalStructureGen/data/BaZn2As2_K-Mn-doped_300K.gr b/docs/examples/pdf/ch06RefineCrystalStructureGen/data/BaZn2As2_K-Mn-doped_300K.gr similarity index 100% rename from docs/examples/ch06RefineCrystalStructureGen/data/BaZn2As2_K-Mn-doped_300K.gr rename to docs/examples/pdf/ch06RefineCrystalStructureGen/data/BaZn2As2_K-Mn-doped_300K.gr diff --git a/docs/examples/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py b/docs/examples/pdf/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py similarity index 100% rename from docs/examples/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py rename to docs/examples/pdf/ch06RefineCrystalStructureGen/solutions/diffpy-cmi/fitCrystalGen.py diff --git a/docs/examples/ch06RefineCrystalStructureGen/solutions/pdfgui/BaZn2As2_mod.cif b/docs/examples/pdf/ch06RefineCrystalStructureGen/solutions/pdfgui/BaZn2As2_mod.cif similarity index 100% rename from docs/examples/ch06RefineCrystalStructureGen/solutions/pdfgui/BaZn2As2_mod.cif rename to docs/examples/pdf/ch06RefineCrystalStructureGen/solutions/pdfgui/BaZn2As2_mod.cif diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_150K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_150K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_150K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_150K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_156K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_156K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_156K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_156K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_162K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_162K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_162K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_162K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_168K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_168K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_168K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_168K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_174K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_174K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_174K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_174K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_180K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_180K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_180K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_180K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_186K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_186K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_186K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_186K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_192K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_192K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_192K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_192K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_198K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_198K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_198K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_198K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_204K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_204K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_204K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_204K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_210K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_210K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_210K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_210K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_216K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_216K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_216K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_216K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_222K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_222K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_222K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_222K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_228K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_228K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_228K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_228K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_234K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_234K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_234K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_234K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_240K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_240K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_240K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_240K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_246K.gr b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_246K.gr similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_246K.gr rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_246K.gr diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_orthorhombic.cif b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_orthorhombic.cif similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_orthorhombic.cif rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_orthorhombic.cif diff --git a/docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_tetragonal.cif b/docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_tetragonal.cif similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/data/SrFe2As2_tetragonal.cif rename to docs/examples/pdf/ch07StructuralPhaseTransitions/data/SrFe2As2_tetragonal.cif diff --git a/docs/examples/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py b/docs/examples/pdf/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py similarity index 100% rename from docs/examples/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py rename to docs/examples/pdf/ch07StructuralPhaseTransitions/solutions/diffpy-cmi/fitTSeries.py diff --git a/docs/examples/ch08NPRefinement/data/CdSe-1.gr b/docs/examples/pdf/ch08NPRefinement/data/CdSe-1.gr similarity index 100% rename from docs/examples/ch08NPRefinement/data/CdSe-1.gr rename to docs/examples/pdf/ch08NPRefinement/data/CdSe-1.gr diff --git a/docs/examples/ch08NPRefinement/data/CdSe-2.gr b/docs/examples/pdf/ch08NPRefinement/data/CdSe-2.gr similarity index 100% rename from docs/examples/ch08NPRefinement/data/CdSe-2.gr rename to docs/examples/pdf/ch08NPRefinement/data/CdSe-2.gr diff --git a/docs/examples/ch08NPRefinement/data/CdSe-3.gr b/docs/examples/pdf/ch08NPRefinement/data/CdSe-3.gr similarity index 100% rename from docs/examples/ch08NPRefinement/data/CdSe-3.gr rename to docs/examples/pdf/ch08NPRefinement/data/CdSe-3.gr diff --git a/docs/examples/ch08NPRefinement/data/CdSe-4.gr b/docs/examples/pdf/ch08NPRefinement/data/CdSe-4.gr similarity index 100% rename from docs/examples/ch08NPRefinement/data/CdSe-4.gr rename to docs/examples/pdf/ch08NPRefinement/data/CdSe-4.gr diff --git a/docs/examples/ch08NPRefinement/data/CdSe-Wurtzite.cif b/docs/examples/pdf/ch08NPRefinement/data/CdSe-Wurtzite.cif similarity index 100% rename from docs/examples/ch08NPRefinement/data/CdSe-Wurtzite.cif rename to docs/examples/pdf/ch08NPRefinement/data/CdSe-Wurtzite.cif diff --git a/docs/examples/ch08NPRefinement/data/CdSe-Zincblende.cif b/docs/examples/pdf/ch08NPRefinement/data/CdSe-Zincblende.cif similarity index 100% rename from docs/examples/ch08NPRefinement/data/CdSe-Zincblende.cif rename to docs/examples/pdf/ch08NPRefinement/data/CdSe-Zincblende.cif diff --git a/docs/examples/ch08NPRefinement/data/CdSe-bulk.gr b/docs/examples/pdf/ch08NPRefinement/data/CdSe-bulk.gr similarity index 100% rename from docs/examples/ch08NPRefinement/data/CdSe-bulk.gr rename to docs/examples/pdf/ch08NPRefinement/data/CdSe-bulk.gr diff --git a/docs/examples/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py b/docs/examples/pdf/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py similarity index 100% rename from docs/examples/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py rename to docs/examples/pdf/ch08NPRefinement/solutions/diffpy-cmi/fitCdSeNP.py diff --git a/docs/examples/ch11ClusterXYZ/data/CdSe.gr b/docs/examples/pdf/ch11ClusterXYZ/data/CdSe.gr similarity index 100% rename from docs/examples/ch11ClusterXYZ/data/CdSe.gr rename to docs/examples/pdf/ch11ClusterXYZ/data/CdSe.gr diff --git a/docs/examples/ch11ClusterXYZ/data/CdSe.xyz b/docs/examples/pdf/ch11ClusterXYZ/data/CdSe.xyz similarity index 100% rename from docs/examples/ch11ClusterXYZ/data/CdSe.xyz rename to docs/examples/pdf/ch11ClusterXYZ/data/CdSe.xyz diff --git a/docs/examples/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py b/docs/examples/pdf/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py similarity index 100% rename from docs/examples/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py rename to docs/examples/pdf/ch11ClusterXYZ/solutions/diffpy-cmi/fitCdSeNP.py From c5c9f84fd8e82e285a6d7e07939978cf063fdb39 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 23 Sep 2025 14:13:03 -0400 Subject: [PATCH 02/21] edit cli to reflect new path change --- src/diffpy/cmi/cli.py | 67 +++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index 50a793e..6cc7010 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -53,17 +53,40 @@ def _installed_examples_dir() -> Path: def list_examples() -> List[str]: - """List installed example names. + """List installed examples grouped by pack. Returns ------- - list of str - Installed example directory names. + dict[str, list[str]] + Mapping of pack name -> list of example subdirectories. """ root = _installed_examples_dir() if not root.exists(): - return [] - return sorted([p.name for p in root.iterdir() if p.is_dir()]) + return {} + + packs: dict[str, list[str]] = {} + for pack_dir in sorted(root.iterdir()): + if not pack_dir.is_dir(): + continue + pack = pack_dir.name + exdirs = sorted([p.name for p in pack_dir.iterdir() if p.is_dir()]) + packs[pack] = exdirs + return packs + + +def print_examples() -> None: + """Print the installed examples grouped by pack.""" + packs = list_examples() + if not packs: + print("No examples found.") + return + for pack, exdirs in packs.items(): + print(pack + ":") + if not exdirs: + print(" (no examples)") + else: + for ex in exdirs: + print(f" - {ex}") def copy_example(example: str) -> Path: @@ -72,7 +95,7 @@ def copy_example(example: str) -> Path: Parameters ---------- example : str - Example directory name under the installed examples root. + Example in the form ``/``. Returns ------- @@ -81,17 +104,25 @@ def copy_example(example: str) -> Path: Raises ------ + ValueError + If the format is invalid. FileNotFoundError If the example directory does not exist. FileExistsError If the destination directory already exists. """ - src = _installed_examples_dir() / example + if "/" not in example: + raise ValueError("Example must be specified as /") + + pack, exdir = example.split("/", 1) + src = _installed_examples_dir() / pack / exdir if not src.exists() or not src.is_dir(): raise FileNotFoundError(f"Example not found: {example}") - dest = Path.cwd() / example + + dest = Path.cwd() / exdir if dest.exists(): raise FileExistsError(f"Destination {dest} already exists") + copytree(src, dest) return dest @@ -163,7 +194,9 @@ def _build_parser() -> argparse.ArgumentParser: _parser=p_example ) p_example_copy = sub_ex.add_parser("copy", help="Copy an example to CWD") - p_example_copy.add_argument("name", metavar="EXAMPLE", help="Example name") + p_example_copy.add_argument( + "name", metavar="EXAMPLE", help="Example name /" + ) p_example_copy.set_defaults(_parser=p_example) p_example.set_defaults(example_cmd=None) @@ -327,7 +360,7 @@ def _cmd_example(ns: argparse.Namespace) -> int: int Exit code (``0`` on success; non-zero on failure). """ - if ns.example_cmd in (None, "copy"): + if ns.example_cmd == "copy": name = getattr(ns, "name", None) if not name: plog.error( @@ -335,12 +368,16 @@ def _cmd_example(ns: argparse.Namespace) -> int: ) ns._parser.print_help() return 1 - out = copy_example(name) - print(f"Example copied to: {out}") - return 0 + try: + out = copy_example(name) + print(f"Example copied to: {out}") + return 0 + except (ValueError, FileNotFoundError, FileExistsError) as e: + plog.error("%s", e) + return 1 + if ns.example_cmd == "list": - for g in list_examples(): - print(g) + print_examples() return 0 plog.error("Unknown example subcommand.") From 1092dcba5a4585c72e0b79e5a7a8e850d6906b70 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 23 Sep 2025 14:13:41 -0400 Subject: [PATCH 03/21] news --- news/ex-path.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/ex-path.rst diff --git a/news/ex-path.rst b/news/ex-path.rst new file mode 100644 index 0000000..e851c41 --- /dev/null +++ b/news/ex-path.rst @@ -0,0 +1,23 @@ +**Added:** + +* Add examples under specific pack name. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 14102ad9b5f4508f9cb0e17e5ac778bb197616d2 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 23 Sep 2025 14:17:31 -0400 Subject: [PATCH 04/21] fix typo --- src/diffpy/cmi/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index 6cc7010..89c6bf9 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -360,7 +360,7 @@ def _cmd_example(ns: argparse.Namespace) -> int: int Exit code (``0`` on success; non-zero on failure). """ - if ns.example_cmd == "copy": + if ns.example_cmd in (None, "copy"): name = getattr(ns, "name", None) if not name: plog.error( From d423377e5cf818508bde74a8cdde679110b7c18a Mon Sep 17 00:00:00 2001 From: Simon Billinge Date: Tue, 23 Sep 2025 20:58:39 -0400 Subject: [PATCH 05/21] Revise examples in news/ex-path.rst for clarity Updated the examples section to include specific pack names and modified the directory structure for clarity. --- news/ex-path.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/news/ex-path.rst b/news/ex-path.rst index e851c41..93e0b7b 100644 --- a/news/ex-path.rst +++ b/news/ex-path.rst @@ -1,10 +1,10 @@ **Added:** -* Add examples under specific pack name. +* **Changed:** -* +* change examples directory structure to insert the name of the ``pack" that the examples exemplify. **Deprecated:** From 683b4c3d79eaaf6a90314a87ea3c401b585360cb Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 24 Sep 2025 22:00:51 -0400 Subject: [PATCH 06/21] rm type hint --- src/diffpy/cmi/cli.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index 89c6bf9..64913b8 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -63,8 +63,7 @@ def list_examples() -> List[str]: root = _installed_examples_dir() if not root.exists(): return {} - - packs: dict[str, list[str]] = {} + packs = {} for pack_dir in sorted(root.iterdir()): if not pack_dir.is_dir(): continue @@ -113,16 +112,13 @@ def copy_example(example: str) -> Path: """ if "/" not in example: raise ValueError("Example must be specified as /") - pack, exdir = example.split("/", 1) src = _installed_examples_dir() / pack / exdir if not src.exists() or not src.is_dir(): raise FileNotFoundError(f"Example not found: {example}") - dest = Path.cwd() / exdir if dest.exists(): raise FileExistsError(f"Destination {dest} already exists") - copytree(src, dest) return dest @@ -375,11 +371,9 @@ def _cmd_example(ns: argparse.Namespace) -> int: except (ValueError, FileNotFoundError, FileExistsError) as e: plog.error("%s", e) return 1 - if ns.example_cmd == "list": print_examples() return 0 - plog.error("Unknown example subcommand.") ns._parser.print_help() return 2 From 3a1ee8b8c6f8b3281cf1082fa4183b1ccb1e5246 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 25 Sep 2025 15:07:33 -0400 Subject: [PATCH 07/21] change list_examples to map_pack_to_examples which returns a dict --- src/diffpy/cmi/cli.py | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index 64913b8..2ab280d 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -52,40 +52,24 @@ def _installed_examples_dir() -> Path: ) -def list_examples() -> List[str]: - """List installed examples grouped by pack. +def map_packs_to_examples() -> dict[str, List[str]]: + """Return a dictionary mapping pack name -> list of example + subdirectories. Returns ------- - dict[str, list[str]] - Mapping of pack name -> list of example subdirectories. + dict: + pack name -> list of example subdirectory names """ root = _installed_examples_dir() if not root.exists(): return {} - packs = {} + examples_by_pack = {} for pack_dir in sorted(root.iterdir()): - if not pack_dir.is_dir(): - continue - pack = pack_dir.name - exdirs = sorted([p.name for p in pack_dir.iterdir() if p.is_dir()]) - packs[pack] = exdirs - return packs - - -def print_examples() -> None: - """Print the installed examples grouped by pack.""" - packs = list_examples() - if not packs: - print("No examples found.") - return - for pack, exdirs in packs.items(): - print(pack + ":") - if not exdirs: - print(" (no examples)") - else: - for ex in exdirs: - print(f" - {ex}") + if pack_dir.is_dir(): + exdirs = sorted(p.name for p in pack_dir.iterdir() if p.is_dir()) + examples_by_pack[pack_dir.name] = exdirs + return examples_by_pack def copy_example(example: str) -> Path: @@ -372,7 +356,10 @@ def _cmd_example(ns: argparse.Namespace) -> int: plog.error("%s", e) return 1 if ns.example_cmd == "list": - print_examples() + for pack, examples in map_packs_to_examples().items(): + print(f"{pack}:") + for ex in examples: + print(f" - {ex}") return 0 plog.error("Unknown example subcommand.") ns._parser.print_help() From d3b531c7e5d90f2b605808a1fb3ce537c8a95d0c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 25 Sep 2025 15:19:18 -0400 Subject: [PATCH 08/21] change variable name to reflect action properly --- src/diffpy/cmi/cli.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index 2ab280d..d531f09 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -72,7 +72,7 @@ def map_packs_to_examples() -> dict[str, List[str]]: return examples_by_pack -def copy_example(example: str) -> Path: +def copy_example(pack_example: str) -> Path: """Copy an example into the current working directory. Parameters @@ -94,12 +94,12 @@ def copy_example(example: str) -> Path: FileExistsError If the destination directory already exists. """ - if "/" not in example: + if "/" not in pack_example: raise ValueError("Example must be specified as /") - pack, exdir = example.split("/", 1) + pack, exdir = pack_example.split("/", 1) src = _installed_examples_dir() / pack / exdir if not src.exists() or not src.is_dir(): - raise FileNotFoundError(f"Example not found: {example}") + raise FileNotFoundError(f"Example not found: {pack_example}") dest = Path.cwd() / exdir if dest.exists(): raise FileExistsError(f"Destination {dest} already exists") @@ -348,13 +348,9 @@ def _cmd_example(ns: argparse.Namespace) -> int: ) ns._parser.print_help() return 1 - try: - out = copy_example(name) - print(f"Example copied to: {out}") - return 0 - except (ValueError, FileNotFoundError, FileExistsError) as e: - plog.error("%s", e) - return 1 + out = copy_example(name) + print(f"Example copied to: {out}") + return 0 if ns.example_cmd == "list": for pack, examples in map_packs_to_examples().items(): print(f"{pack}:") From 73d083ed95711e24b6e4739d78630bc22ed78c64 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 25 Sep 2025 15:21:41 -0400 Subject: [PATCH 09/21] change function name --- src/diffpy/cmi/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index d531f09..762f526 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -52,7 +52,7 @@ def _installed_examples_dir() -> Path: ) -def map_packs_to_examples() -> dict[str, List[str]]: +def get_examples_by_pack() -> dict[str, List[str]]: """Return a dictionary mapping pack name -> list of example subdirectories. @@ -352,7 +352,7 @@ def _cmd_example(ns: argparse.Namespace) -> int: print(f"Example copied to: {out}") return 0 if ns.example_cmd == "list": - for pack, examples in map_packs_to_examples().items(): + for pack, examples in get_examples_by_pack().items(): print(f"{pack}:") for ex in examples: print(f" - {ex}") From 61a9bd6d44ca3c5067450be93b5df093addcb13e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 25 Sep 2025 16:07:56 -0400 Subject: [PATCH 10/21] update docstring --- src/diffpy/cmi/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index 762f526..055bd24 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -78,7 +78,7 @@ def copy_example(pack_example: str) -> Path: Parameters ---------- example : str - Example in the form ``/``. + Pack and example name in the form ``/``. Returns ------- From d90a2715596a204a3a1ef5e91f8065b1b58de6e2 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 25 Sep 2025 17:10:28 -0400 Subject: [PATCH 11/21] tests for help command, listing examples, and copying examples --- tests/test_cli.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/test_cli.py diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..c66cd90 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,39 @@ +import pytest + +from diffpy.cmi.cli import main + + +def test_cli_help(capsys): + """Test that the CLI help message is displayed correctly.""" + with pytest.raises(SystemExit) as exc: + main(["--help", "-h"]) + assert exc.value.code == 0 + out, _ = capsys.readouterr() + assert "Welcome to diffpy.cmi" in out + + +def test_example_list(capsys): + """Test that the example listing works.""" + rc = main(["example", "list"]) + assert rc == 0 + out, _ = capsys.readouterr() + # test specific known pack and example + assert "ch03NiModelling" in out + assert "pdf" in out + + +def test_example_copy(monkeypatch, tmp_path): + """Test that an example can be copied to the current directory.""" + # create a fake example + fake_examples = tmp_path / "docs" / "examples" + src = fake_examples / "pack1" / "ex1" + src.mkdir(parents=True) + monkeypatch.setattr( + "diffpy.cmi.cli._installed_examples_dir", + lambda: fake_examples, + ) + cwd = tmp_path + monkeypatch.chdir(cwd) + rc = main(["example", "copy", "pdf/ch03NiModelling"]) + assert rc == 0 + assert (cwd / "ch03NiModelling").exists() From c12f6b558ec6971a4a87444b51b3f949de402672 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 25 Sep 2025 17:12:54 -0400 Subject: [PATCH 12/21] fix monkeypatch debugging code --- tests/test_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index c66cd90..74f9a49 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -34,6 +34,6 @@ def test_example_copy(monkeypatch, tmp_path): ) cwd = tmp_path monkeypatch.chdir(cwd) - rc = main(["example", "copy", "pdf/ch03NiModelling"]) + rc = main(["example", "copy", "pack1/ex1"]) assert rc == 0 - assert (cwd / "ch03NiModelling").exists() + assert (cwd / "ex1").exists() From c0bead8d7838a0d919bd13d9c1811ec7a0151084 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 26 Sep 2025 10:29:26 -0400 Subject: [PATCH 13/21] update function names to be more readable --- src/diffpy/cmi/cli.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index 7c629de..f130ae0 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -26,7 +26,7 @@ # Examples -def _installed_examples_dir() -> Path: +def _get_examples_dir() -> Path: """Return the absolute path to the installed examples directory. Returns @@ -52,7 +52,7 @@ def _installed_examples_dir() -> Path: ) -def get_examples_by_pack() -> dict[str, List[str]]: +def map_pack_to_examples() -> dict[str, List[str]]: """Return a dictionary mapping pack name -> list of example subdirectories. @@ -61,7 +61,7 @@ def get_examples_by_pack() -> dict[str, List[str]]: dict: pack name -> list of example subdirectory names """ - root = _installed_examples_dir() + root = _get_examples_dir() if not root.exists(): return {} examples_by_pack = {} @@ -97,7 +97,7 @@ def copy_example(pack_example: str) -> Path: if "/" not in pack_example: raise ValueError("Example must be specified as /") pack, exdir = pack_example.split("/", 1) - src = _installed_examples_dir() / pack / exdir + src = _get_examples_dir() / pack / exdir if not src.exists() or not src.is_dir(): raise FileNotFoundError(f"Example not found: {pack_example}") dest = Path.cwd() / exdir @@ -352,7 +352,7 @@ def _cmd_example(ns: argparse.Namespace) -> int: print(f"Example copied to: {out}") return 0 if ns.example_cmd == "list": - for pack, examples in get_examples_by_pack().items(): + for pack, examples in map_pack_to_examples().items(): print(f"{pack}:") for ex in examples: print(f" - {ex}") From 63ac630a7ec68e5453f4d02b0fcfe8014f31eb87 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 26 Sep 2025 10:30:29 -0400 Subject: [PATCH 14/21] test map pack to examples function --- tests/test_cli.py | 69 +++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 74f9a49..ffe0ca1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,39 +1,38 @@ import pytest -from diffpy.cmi.cli import main +from diffpy.cmi import cli -def test_cli_help(capsys): - """Test that the CLI help message is displayed correctly.""" - with pytest.raises(SystemExit) as exc: - main(["--help", "-h"]) - assert exc.value.code == 0 - out, _ = capsys.readouterr() - assert "Welcome to diffpy.cmi" in out - - -def test_example_list(capsys): - """Test that the example listing works.""" - rc = main(["example", "list"]) - assert rc == 0 - out, _ = capsys.readouterr() - # test specific known pack and example - assert "ch03NiModelling" in out - assert "pdf" in out - - -def test_example_copy(monkeypatch, tmp_path): - """Test that an example can be copied to the current directory.""" - # create a fake example - fake_examples = tmp_path / "docs" / "examples" - src = fake_examples / "pack1" / "ex1" - src.mkdir(parents=True) - monkeypatch.setattr( - "diffpy.cmi.cli._installed_examples_dir", - lambda: fake_examples, - ) - cwd = tmp_path - monkeypatch.chdir(cwd) - rc = main(["example", "copy", "pack1/ex1"]) - assert rc == 0 - assert (cwd / "ex1").exists() +@pytest.mark.parametrize( + "structure, expected", + [ + # case: one pack with one example + ([("packA", ["ex1"])], {"packA": ["ex1"]}), + # case: one pack with multiple examples + ([("packA", ["ex1", "ex2"])], {"packA": ["ex1", "ex2"]}), + # case: multiple packs with one example each + ( + [("packA", ["ex1"]), ("packB", ["ex2"])], + {"packA": ["ex1"], "packB": ["ex2"]}, + ), + # case: multiple packs with multiple examples + ( + [("packA", ["ex1", "ex2"]), ("packB", ["ex3", "ex4"])], + {"packA": ["ex1", "ex2"], "packB": ["ex3", "ex4"]}, + ), + ], +) +def test_map_pack_to_examples(tmp_path, mocker, structure, expected): + """Finds examples directory and returns a dictionary mapping packs + to examples.""" + # example input: build example structure + for pack, exdirs in structure: + packdir = tmp_path / pack + packdir.mkdir() + for ex in exdirs: + (packdir / ex).mkdir() + # patch _get_examples_dir to point to tmp_path + mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) + # expected behavior: a dictionary mapping pack to lists of examples + result = cli.map_pack_to_examples() + assert result == expected From e0a2c75ca6b7a0683f2ce234160e98a37760b615 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 26 Sep 2025 10:32:44 -0400 Subject: [PATCH 15/21] add no packs, no examples case --- tests/test_cli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_cli.py b/tests/test_cli.py index ffe0ca1..5afc739 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -6,6 +6,8 @@ @pytest.mark.parametrize( "structure, expected", [ + # case: no packs, no examples + ([], {}), # case: one pack with one example ([("packA", ["ex1"])], {"packA": ["ex1"]}), # case: one pack with multiple examples From 81fa5cf82127d0c818c9ba6200adcdd72b3d204b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 26 Sep 2025 10:37:48 -0400 Subject: [PATCH 16/21] make sure directory was created --- tests/test_cli.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 5afc739..19a3948 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -32,9 +32,17 @@ def test_map_pack_to_examples(tmp_path, mocker, structure, expected): packdir = tmp_path / pack packdir.mkdir() for ex in exdirs: - (packdir / ex).mkdir() + exdir = packdir / ex + exdir.mkdir() + # check directory was created + assert exdir.exists() and exdir.is_dir(), f"{exdir} not created" # patch _get_examples_dir to point to tmp_path mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) # expected behavior: a dictionary mapping pack to lists of examples result = cli.map_pack_to_examples() assert result == expected + + +def test_copy_examples(): + """""" + return From 10771b15cd17803b74569e473dfeb723762929f5 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 26 Sep 2025 14:34:40 -0400 Subject: [PATCH 17/21] add tests for copy_example --- tests/test_cli.py | 88 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 19a3948..e36a6cd 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,48 +1,100 @@ +import os + import pytest from diffpy.cmi import cli @pytest.mark.parametrize( - "structure, expected", + "inputs, expected", [ - # case: no packs, no examples + # case: no packs, no examples, expect empty dict ([], {}), - # case: one pack with one example + # case: one pack with one example, + # expect dict of {"pack-name": ["example"]} ([("packA", ["ex1"])], {"packA": ["ex1"]}), - # case: one pack with multiple examples + # case: one pack with multiple examples, + # expect dict of {"pack-name": ["example1", "example2"]} ([("packA", ["ex1", "ex2"])], {"packA": ["ex1", "ex2"]}), - # case: multiple packs with one example each + # case: multiple packs with one example each, + # expect dict of {"pack-name": ["example"]} ( [("packA", ["ex1"]), ("packB", ["ex2"])], {"packA": ["ex1"], "packB": ["ex2"]}, ), - # case: multiple packs with multiple examples + # case: multiple packs with multiple examples, + # expect dict of {"pack-name": ["example1", "example2"]} ( [("packA", ["ex1", "ex2"]), ("packB", ["ex3", "ex4"])], {"packA": ["ex1", "ex2"], "packB": ["ex3", "ex4"]}, ), ], ) -def test_map_pack_to_examples(tmp_path, mocker, structure, expected): +def test_map_pack_to_examples(tmp_path, mocker, inputs, expected): """Finds examples directory and returns a dictionary mapping packs to examples.""" - # example input: build example structure - for pack, exdirs in structure: - packdir = tmp_path / pack + for pack_name, example_list in inputs: + packdir = tmp_path / pack_name packdir.mkdir() - for ex in exdirs: - exdir = packdir / ex + for example in example_list: + exdir = packdir / example exdir.mkdir() - # check directory was created - assert exdir.exists() and exdir.is_dir(), f"{exdir} not created" # patch _get_examples_dir to point to tmp_path mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) - # expected behavior: a dictionary mapping pack to lists of examples result = cli.map_pack_to_examples() assert result == expected -def test_copy_examples(): - """""" - return +def test_copy_example_success(tmp_path, mocker): + """Tests successful copy of example from pack to cwd.""" + pack, ex = "pack1", "ex1" + example_dir = tmp_path / pack / ex + example_dir.mkdir(parents=True) + # Patch _get_examples_dir to use tmp_path + mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) + os.chdir(tmp_path) + dest = cli.copy_example(f"{pack}/{ex}") + expected_dest = tmp_path / ex + assert dest == expected_dest + assert dest.exists() + + +@pytest.mark.parametrize("bad_input", ["pack1ex1", "pack1/", "/ex1"]) +def test_copy_example_invalid_format(tmp_path, mocker, bad_input): + """Tests invalid format ValueError.""" + mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) + os.chdir(tmp_path) + with pytest.raises(ValueError): + cli.copy_example(bad_input) + + +@pytest.mark.parametrize( + "pack, ex", + [ + ("pack1", "ex1"), + ("missing_pack", "ex1"), + ], +) +def test_copy_example_not_found(tmp_path, mocker, pack, ex): + """ + Test copy_example raises FileNotFoundError when: + - the pack exists but example is missing + - the pack itself is missing + """ + mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) + os.chdir(tmp_path) + with pytest.raises(FileNotFoundError): + cli.copy_example(f"{pack}/{ex}") + + +def test_copy_example_destination_exists(tmp_path, mocker): + """Tests FileExistsError when destination directory already + exists.""" + pack, ex = "pack1", "ex1" + example_dir = tmp_path / pack / ex + example_dir.mkdir(parents=True) + mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) + os.chdir(tmp_path) + (tmp_path / ex).mkdir(exist_ok=True) + with pytest.raises(FileExistsError): + cli.copy_example(f"{pack}/{ex}") From 4ee36af5f29492b8ae3754c3620e0ada9fb07dfd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 26 Sep 2025 14:35:04 -0400 Subject: [PATCH 18/21] Add Error if pack or example doesnt exist --- src/diffpy/cmi/cli.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index f130ae0..0aaddb3 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -77,7 +77,7 @@ def copy_example(pack_example: str) -> Path: Parameters ---------- - example : str + pack_example : str Pack and example name in the form ``/``. Returns @@ -88,7 +88,7 @@ def copy_example(pack_example: str) -> Path: Raises ------ ValueError - If the format is invalid. + If the format is invalid (missing pack or example). FileNotFoundError If the example directory does not exist. FileExistsError @@ -97,6 +97,11 @@ def copy_example(pack_example: str) -> Path: if "/" not in pack_example: raise ValueError("Example must be specified as /") pack, exdir = pack_example.split("/", 1) + if not pack or not exdir: + raise ValueError( + f"Invalid format for example '{pack_example}'. " + "Must be '/'" + ) src = _get_examples_dir() / pack / exdir if not src.exists() or not src.is_dir(): raise FileNotFoundError(f"Example not found: {pack_example}") From 65fd2c70d6511e47767696bb4f2a27d16b204bd7 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 29 Sep 2025 10:09:02 -0400 Subject: [PATCH 19/21] map packs function test, simplified --- tests/test_cli.py | 110 ++++++---------------------------------------- 1 file changed, 14 insertions(+), 96 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index e36a6cd..103794a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,100 +1,18 @@ -import os - -import pytest - from diffpy.cmi import cli -@pytest.mark.parametrize( - "inputs, expected", - [ - # case: no packs, no examples, expect empty dict - ([], {}), - # case: one pack with one example, - # expect dict of {"pack-name": ["example"]} - ([("packA", ["ex1"])], {"packA": ["ex1"]}), - # case: one pack with multiple examples, - # expect dict of {"pack-name": ["example1", "example2"]} - ([("packA", ["ex1", "ex2"])], {"packA": ["ex1", "ex2"]}), - # case: multiple packs with one example each, - # expect dict of {"pack-name": ["example"]} - ( - [("packA", ["ex1"]), ("packB", ["ex2"])], - {"packA": ["ex1"], "packB": ["ex2"]}, - ), - # case: multiple packs with multiple examples, - # expect dict of {"pack-name": ["example1", "example2"]} - ( - [("packA", ["ex1", "ex2"]), ("packB", ["ex3", "ex4"])], - {"packA": ["ex1", "ex2"], "packB": ["ex3", "ex4"]}, - ), - ], -) -def test_map_pack_to_examples(tmp_path, mocker, inputs, expected): - """Finds examples directory and returns a dictionary mapping packs - to examples.""" - for pack_name, example_list in inputs: - packdir = tmp_path / pack_name - packdir.mkdir() - for example in example_list: - exdir = packdir / example - exdir.mkdir() - # patch _get_examples_dir to point to tmp_path - mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) +def test_map_pack_to_examples_structure(): + """Test that map_pack_to_examples returns the right shape of + data.""" result = cli.map_pack_to_examples() - assert result == expected - - -def test_copy_example_success(tmp_path, mocker): - """Tests successful copy of example from pack to cwd.""" - pack, ex = "pack1", "ex1" - example_dir = tmp_path / pack / ex - example_dir.mkdir(parents=True) - # Patch _get_examples_dir to use tmp_path - mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) - os.chdir(tmp_path) - dest = cli.copy_example(f"{pack}/{ex}") - expected_dest = tmp_path / ex - assert dest == expected_dest - assert dest.exists() - - -@pytest.mark.parametrize("bad_input", ["pack1ex1", "pack1/", "/ex1"]) -def test_copy_example_invalid_format(tmp_path, mocker, bad_input): - """Tests invalid format ValueError.""" - mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) - os.chdir(tmp_path) - with pytest.raises(ValueError): - cli.copy_example(bad_input) - - -@pytest.mark.parametrize( - "pack, ex", - [ - ("pack1", "ex1"), - ("missing_pack", "ex1"), - ], -) -def test_copy_example_not_found(tmp_path, mocker, pack, ex): - """ - Test copy_example raises FileNotFoundError when: - - the pack exists but example is missing - - the pack itself is missing - """ - mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) - os.chdir(tmp_path) - with pytest.raises(FileNotFoundError): - cli.copy_example(f"{pack}/{ex}") - - -def test_copy_example_destination_exists(tmp_path, mocker): - """Tests FileExistsError when destination directory already - exists.""" - pack, ex = "pack1", "ex1" - example_dir = tmp_path / pack / ex - example_dir.mkdir(parents=True) - mocker.patch.object(cli, "_get_examples_dir", return_value=tmp_path) - os.chdir(tmp_path) - (tmp_path / ex).mkdir(exist_ok=True) - with pytest.raises(FileExistsError): - cli.copy_example(f"{pack}/{ex}") + assert isinstance(result, dict) + for pack, exdirs in result.items(): + assert isinstance(pack, str) + assert isinstance(exdirs, list) + for ex in exdirs: + assert isinstance(ex, str) + # Check for known packs + assert "core" in result.keys() + assert "pdf" in result.keys() + # Check for known examples + assert ["linefit"] in result.values() From 74e992b6df5f39baa02afcf4277bb790f2b8970a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 29 Sep 2025 10:34:05 -0400 Subject: [PATCH 20/21] add condition that catches extra slashes --- src/diffpy/cmi/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffpy/cmi/cli.py b/src/diffpy/cmi/cli.py index 0aaddb3..f25cb78 100644 --- a/src/diffpy/cmi/cli.py +++ b/src/diffpy/cmi/cli.py @@ -94,7 +94,7 @@ def copy_example(pack_example: str) -> Path: FileExistsError If the destination directory already exists. """ - if "/" not in pack_example: + if "/" not in pack_example or pack_example.count("/") != 1: raise ValueError("Example must be specified as /") pack, exdir = pack_example.split("/", 1) if not pack or not exdir: From d53fab8c71c6bf4d4c21e2f4b4643ad6577a8cde Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 29 Sep 2025 10:34:18 -0400 Subject: [PATCH 21/21] test copy behavior --- tests/test_cli.py | 59 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 103794a..9eb9712 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,18 +1,65 @@ +import os +from pathlib import Path + +import pytest + from diffpy.cmi import cli def test_map_pack_to_examples_structure(): """Test that map_pack_to_examples returns the right shape of data.""" - result = cli.map_pack_to_examples() - assert isinstance(result, dict) - for pack, exdirs in result.items(): + actual = cli.map_pack_to_examples() + assert isinstance(actual, dict) + for pack, exdirs in actual.items(): assert isinstance(pack, str) assert isinstance(exdirs, list) for ex in exdirs: assert isinstance(ex, str) # Check for known packs - assert "core" in result.keys() - assert "pdf" in result.keys() + assert "core" in actual.keys() + assert "pdf" in actual.keys() # Check for known examples - assert ["linefit"] in result.values() + assert ["linefit"] in actual.values() + + +@pytest.mark.parametrize( + "input_valid_str", + [ + "core/linefit", + "pdf/ch03NiModelling", + ], +) +def test_copy_example_success(tmp_path, input_valid_str): + """Given a valid example format (/), test that its copied + to the temp dir.""" + os.chdir(tmp_path) + actual = cli.copy_example(input_valid_str) + expected = tmp_path / Path(input_valid_str).name + assert expected.exists() and expected.is_dir() + assert actual == expected + + +def test_copy_example_fnferror(): + """Test that FileNotFoundError is raised when the example does not + exist.""" + with pytest.raises(FileNotFoundError): + cli.copy_example("pack/example1") + + +@pytest.mark.parametrize( + "input_bad_str", + [ + "", # empty string + "/", # missing pack and example + "corelinefit", # missing slash + "linefit", # missing pack and slash + "core/", # missing example + "/linefit", # missing pack + "core/linefit/extra", # too many slashes + ], +) +def test_copy_example_valueerror(input_bad_str): + """Test that ValueError is raised when the format is invalid.""" + with pytest.raises(ValueError): + cli.copy_example(input_bad_str)