diffpy.apps 0.2.0rc0__tar.gz → 0.2.0rc1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. {diffpy_apps-0.2.0rc0/src/diffpy.apps.egg-info → diffpy_apps-0.2.0rc1}/PKG-INFO +3 -3
  2. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/pyproject.toml +1 -2
  3. diffpy_apps-0.2.0rc1/src/diffpy/__init__.py +14 -0
  4. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/app_agentify.py +22 -12
  5. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/pdfadapter.py +0 -1
  6. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/refinebase/parametric_model.py +6 -7
  7. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/refinebase/refinement_server.py +22 -30
  8. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1/src/diffpy.apps.egg-info}/PKG-INFO +3 -3
  9. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/test_agentify.py +9 -6
  10. diffpy_apps-0.2.0rc0/src/diffpy/apps/refinebase/__init__.py +0 -0
  11. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/AUTHORS.rst +0 -0
  12. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/LICENSE.rst +0 -0
  13. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/MANIFEST.in +0 -0
  14. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/README.rst +0 -0
  15. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/requirements/build.txt +0 -0
  16. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/requirements/conda.txt +0 -0
  17. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/requirements/docs.txt +0 -0
  18. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/requirements/pip.txt +0 -0
  19. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/requirements/tests.txt +0 -0
  20. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/setup.cfg +0 -0
  21. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/__init__.py +0 -0
  22. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/app_runmacro.py +0 -0
  23. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/apps.py +0 -0
  24. {diffpy_apps-0.2.0rc0/src/diffpy → diffpy_apps-0.2.0rc1/src/diffpy/apps/refinebase}/__init__.py +0 -0
  25. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/refinebase/refinement_session.py +0 -0
  26. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy/apps/version.py +0 -0
  27. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy.apps.egg-info/SOURCES.txt +0 -0
  28. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy.apps.egg-info/dependency_links.txt +0 -0
  29. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy.apps.egg-info/entry_points.txt +0 -0
  30. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy.apps.egg-info/requires.txt +0 -0
  31. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/src/diffpy.apps.egg-info/top_level.txt +0 -0
  32. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/conftest.py +0 -0
  33. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/C60.gr +0 -0
  34. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/Ni.cif +0 -0
  35. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/Ni.gr +0 -0
  36. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/c60xyz.txt +0 -0
  37. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/make_c60.txt +0 -0
  38. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/ni-q27r100-neutron.gr +0 -0
  39. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/ni-q27r60-xray.gr +0 -0
  40. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/pb.cif +0 -0
  41. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/pb_100_qmin1.gr +0 -0
  42. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/si-q27r60-xray.gr +0 -0
  43. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/si.cif +0 -0
  44. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/si90ni10-q27r60-xray.gr +0 -0
  45. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/data/sine.dat +0 -0
  46. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/helper.py +0 -0
  47. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/test_parametric_model.py +0 -0
  48. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/test_pdfadapter.py +0 -0
  49. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/test_refinement_server.py +0 -0
  50. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/test_refinement_session.py +0 -0
  51. {diffpy_apps-0.2.0rc0 → diffpy_apps-0.2.0rc1}/tests/test_runmacro.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffpy.apps
3
- Version: 0.2.0rc0
3
+ Version: 0.2.0rc1
4
4
  Summary: User applications to help with tasks using diffpy packages
5
- Author-email: Yuchen Xiao <yx2924@columbia.edu>, Simon Billinge <sbillinge@ucsb.edu>
6
- Maintainer-email: Yuchen Xiao <yx2924@columbia.edu>, Simon Billinge <sbillinge@ucsb.edu>
5
+ Author-email: Yuchen Xiao <xiaoyuch@msu.edu>, Simon Billinge <sbillinge@ucsb.edu>
6
+ Maintainer-email: Simon Billinge <sbillinge@ucsb.edu>
7
7
  License-Expression: BSD-3-Clause
8
8
  Project-URL: Homepage, https://github.com/diffpy/diffpy.apps/
9
9
  Project-URL: Issues, https://github.com/diffpy/diffpy.apps/issues/
@@ -6,11 +6,10 @@ build-backend = "setuptools.build_meta"
6
6
  name = "diffpy.apps"
7
7
  dynamic=['version', 'dependencies']
8
8
  authors = [
9
- {name='Yuchen Xiao', email='yx2924@columbia.edu'},
9
+ {name='Yuchen Xiao', email='xiaoyuch@msu.edu'},
10
10
  {name='Simon Billinge', email='sbillinge@ucsb.edu'},
11
11
  ]
12
12
  maintainers = [
13
- {name='Yuchen Xiao', email='yx2924@columbia.edu'},
14
13
  {name='Simon Billinge', email='sbillinge@ucsb.edu'},
15
14
  ]
16
15
  description = "User applications to help with tasks using diffpy packages"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # (c) 2026 diffpy.apps contributors.
5
+ # All rights reserved.
6
+ #
7
+ # File coded by: Billinge Group members and community contributors.
8
+ #
9
+ # See GitHub contributions for a more detailed list of contributors.
10
+ # https://github.com/diffpy/diffpy.apps/graphs/contributors
11
+ #
12
+ # See LICENSE.rst for license information.
13
+ #
14
+ ##############################################################################
@@ -2,10 +2,10 @@ import shutil
2
2
  import socket
3
3
  import subprocess
4
4
  import tempfile
5
+ import warnings
5
6
  from pathlib import Path
6
7
 
7
8
  REPO_URL = "https://github.com/diffpy/cmi-agent-skills"
8
- DIR_NAME = "cmi-skill"
9
9
 
10
10
 
11
11
  def ensure_setup():
@@ -35,21 +35,31 @@ def agentify(args):
35
35
  elif agent == "codex":
36
36
  skills_dir = ".codex/skills"
37
37
  if system_flag:
38
- destination = Path().home() / skills_dir / DIR_NAME
38
+ dest_dir = Path().home() / skills_dir
39
39
  else:
40
- destination = Path().cwd() / skills_dir / DIR_NAME
41
- if destination.exists() and not args.update:
42
- raise FileExistsError(
43
- f"Agentic skill {DIR_NAME} already exists at {destination}. "
44
- "To overwrite, pass '--update' flag to update the skill"
45
- )
40
+ dest_dir = Path().cwd() / skills_dir
46
41
  with tempfile.TemporaryDirectory() as tmp:
47
42
  tmp_path = Path(tmp)
48
43
  subprocess.run(
49
44
  ["git", "clone", REPO_URL, str(tmp_path)],
50
45
  check=True,
51
46
  )
52
- if destination.exists():
53
- shutil.rmtree(destination)
54
- shutil.copytree(tmp_path / DIR_NAME, destination, dirs_exist_ok=True)
55
- print(f"Agentic skill {DIR_NAME} has been deployed to {destination}")
47
+ for item in tmp_path.iterdir():
48
+ if item.is_dir():
49
+ destination = dest_dir / item.name
50
+ if destination.exists():
51
+ if args.update:
52
+ shutil.rmtree(destination)
53
+ shutil.copytree(item, destination, dirs_exist_ok=True)
54
+ print(f"Updated existing skill at {destination}")
55
+ else:
56
+ warnings.warn(
57
+ f"Skill at {destination} already exists. "
58
+ "Use '--update' flag to overwrite."
59
+ )
60
+ continue
61
+ else:
62
+ shutil.copytree(item, destination, dirs_exist_ok=True)
63
+ print(
64
+ f"Skill {item.name} has been deployed to {destination}"
65
+ )
@@ -202,7 +202,6 @@ class PDFAdapter:
202
202
  delta1 and delta2 variables, and structure parameters
203
203
  constrained by the space group.
204
204
  """
205
-
206
205
  recipe = FitRecipe()
207
206
  recipe.add_contribution(self.contribution)
208
207
  qdamp = recipe.create_new_variable("qdamp", fixed=False, value=0.04)
@@ -199,8 +199,7 @@ class ParametricModelEquation(ParametricModel):
199
199
 
200
200
  class ParametricModelFunction(ParametricModel):
201
201
  def __init__(self, name, function, argnames=None):
202
- """
203
- Initialize a ParametricModelFunction instance.
202
+ """Initialize a ParametricModelFunction instance.
204
203
 
205
204
  function can be either a callable or a string representing
206
205
  the pre-defined function.
@@ -254,8 +253,7 @@ class ParametricModelPDF(ParametricModel):
254
253
  finite=False,
255
254
  run_parallel=True,
256
255
  ):
257
- """
258
- Create a ParametricModelPDF instance from a structure object.
256
+ """Create a ParametricModelPDF instance from a structure object.
259
257
 
260
258
  structure can be a raw diffpy.structure/pyobjcryst structure, or
261
259
  an existing DiffpyStructureParSet/ObjCrystCrystalParSet phase
@@ -615,10 +613,11 @@ def create_pdf_model_from_code(
615
613
  finite=False,
616
614
  run_parallel=True,
617
615
  ):
618
- """Create a ParametricModelPDF by executing code that builds a structure.
616
+ """Create a ParametricModelPDF by executing code that builds a
617
+ structure.
619
618
 
620
- The code must assign the structure/crystal object to a variable named
621
- structure_name (default "structure") in its local namespace.
619
+ The code must assign the structure/crystal object to a variable
620
+ named structure_name (default "structure") in its local namespace.
622
621
  """
623
622
  local_namespace = {}
624
623
  exec(code, global_namespace, local_namespace)
@@ -102,7 +102,8 @@ async def set_profile_calculation_range(
102
102
  xmax: Annotated[float, "End of the calculation range"] = None,
103
103
  dx: Annotated[float, "Step size for the calculation range"] = None,
104
104
  ) -> str:
105
- """Set the calculation range for a profile in the refinement session."""
105
+ """Set the calculation range for a profile in the refinement
106
+ session."""
106
107
  session.set_profile_calculation_range(
107
108
  profile_name, xmin=xmin, xmax=xmax, dx=dx
108
109
  )
@@ -191,8 +192,8 @@ async def add_pdf_model(
191
192
  bool, "Whether to run the PDF model in parallel"
192
193
  ] = True,
193
194
  ) -> str:
194
- """
195
- Add a structure-file-based parametric model to the refinement session.
195
+ """Add a structure-file-based parametric model to the refinement
196
+ session.
196
197
 
197
198
  Parameters
198
199
  ----------
@@ -247,8 +248,7 @@ async def add_function_model(
247
248
  list[str] | None, "Argument names for the function"
248
249
  ] = None,
249
250
  ) -> str:
250
- """
251
- Add a function model to the refinement session.
251
+ """Add a function model to the refinement session.
252
252
 
253
253
  function can be either a callable or a string representing
254
254
  the pre-defined function.
@@ -282,7 +282,8 @@ async def set_model_equation(
282
282
  model_name: Annotated[str, "Name of the parametric model"],
283
283
  equation: Annotated[str, "New equation for the parametric model"],
284
284
  ) -> str:
285
- """Set the equation for an existing parametric model in the session."""
285
+ """Set the equation for an existing parametric model in the
286
+ session."""
286
287
  session.set_model_equation(model_name=model_name, equation=equation)
287
288
  return f"Equation for model {model_name} set successfully."
288
289
 
@@ -339,7 +340,8 @@ async def set_model_profile(
339
340
  model_name: Annotated[str, "Name of the parametric model"],
340
341
  profile_name: Annotated[str, "Name of the profile to set on the model"],
341
342
  ) -> str:
342
- """Set the profile for a parametric model in the refinement session."""
343
+ """Set the profile for a parametric model in the refinement
344
+ session."""
343
345
  session.set_model_profile(model_name, profile_name)
344
346
  return f"Profile {profile_name} set for model {model_name} successfully."
345
347
 
@@ -365,7 +367,8 @@ async def get_profile_data(
365
367
  profile_name: Annotated[str, "Name of the profile to retrieve"],
366
368
  data_path: Annotated[str, "Path to the data to retrieve"],
367
369
  ) -> str:
368
- """Get the details of a specific profile in the refinement session."""
370
+ """Get the details of a specific profile in the refinement
371
+ session."""
369
372
  profile = session.profiles_dict[profile_name]
370
373
  data = {"xobs": profile.xobs.tolist(), "yobs": profile.yobs.tolist()}
371
374
  with open(data_path, "w") as f:
@@ -395,8 +398,8 @@ async def constrain_pdf_model_space_group_symmetry(
395
398
  ) -> str:
396
399
  """Constrain a parametric model to a specific space group symmetry.
397
400
 
398
- If no space group is provided, the model will be constrained to
399
- its current space group parsed from its structure.
401
+ If no space group is provided, the model will be constrained to its
402
+ current space group parsed from its structure.
400
403
  """
401
404
  session.constrain_pdf_model_space_group_symmetry(model_name, space_group)
402
405
  return (
@@ -428,9 +431,8 @@ async def combine_models(
428
431
  list[str], "Names of the child parametric models"
429
432
  ],
430
433
  ) -> str:
431
- """
432
- Combine two parametric models by registering the child to the parent model.
433
- """
434
+ """Combine two parametric models by registering the child to the
435
+ parent model."""
434
436
  session.combine_models(parent_model_name, child_model_names)
435
437
  return (
436
438
  f"Models {parent_model_name} and "
@@ -445,9 +447,7 @@ async def set_variables_value(
445
447
  dict, "Mapping of variable names to the values to set them to"
446
448
  ],
447
449
  ) -> str:
448
- """
449
- Set the value of a specific variable in a parametric model.
450
- """
450
+ """Set the value of a specific variable in a parametric model."""
451
451
  session.set_variables_value(name_value_dict)
452
452
 
453
453
  return f"Variables '{name_value_dict}' are set."
@@ -458,9 +458,7 @@ async def set_variables_value(
458
458
  async def get_variable(
459
459
  variable_name: Annotated[str, "Name of the variable"],
460
460
  ) -> str:
461
- """
462
- Get the value of a specific variable in a parametric model.
463
- """
461
+ """Get the value of a specific variable in a parametric model."""
464
462
  variable = session.get_variable(variable_name)
465
463
  return f"Variable '{variable_name}': {variable['value']}"
466
464
 
@@ -473,9 +471,7 @@ async def list_model_parameters(
473
471
  bool, "Whether to list only independent parameters"
474
472
  ] = True,
475
473
  ) -> str:
476
- """
477
- List all parameters of a specific parametric model.
478
- """
474
+ """List all parameters of a specific parametric model."""
479
475
  if model_name not in session.models_dict:
480
476
  raise ValueError(f"Model with ID {model_name} does not exist.")
481
477
 
@@ -495,9 +491,7 @@ async def list_model_parameters(
495
491
  @mcp.tool()
496
492
  @tool_errors
497
493
  async def clear() -> str:
498
- """
499
- Clear the current refinement session.
500
- """
494
+ """Clear the current refinement session."""
501
495
  session.clear()
502
496
  return "Refinement session cleared successfully."
503
497
 
@@ -507,9 +501,7 @@ async def clear() -> str:
507
501
  async def list_recipe_parameters(
508
502
  recipe_name: Annotated[str, "Name of the recipe"],
509
503
  ) -> str:
510
- """
511
- List all parameters of a specific recipe.
512
- """
504
+ """List all parameters of a specific recipe."""
513
505
  if recipe_name not in session.recipes_dict:
514
506
  raise ValueError(f"Recipe with ID {recipe_name} does not exist.")
515
507
 
@@ -552,8 +544,8 @@ async def solve(
552
544
  bool, "Whether to also include sgpars from the models automatically"
553
545
  ] = False,
554
546
  ) -> str:
555
- """
556
- Initiate a refinement using the specified profiles, models, and variables.
547
+ """Initiate a refinement using the specified profiles, models, and
548
+ variables.
557
549
 
558
550
  Parameters
559
551
  ----------
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffpy.apps
3
- Version: 0.2.0rc0
3
+ Version: 0.2.0rc1
4
4
  Summary: User applications to help with tasks using diffpy packages
5
- Author-email: Yuchen Xiao <yx2924@columbia.edu>, Simon Billinge <sbillinge@ucsb.edu>
6
- Maintainer-email: Yuchen Xiao <yx2924@columbia.edu>, Simon Billinge <sbillinge@ucsb.edu>
5
+ Author-email: Yuchen Xiao <xiaoyuch@msu.edu>, Simon Billinge <sbillinge@ucsb.edu>
6
+ Maintainer-email: Simon Billinge <sbillinge@ucsb.edu>
7
7
  License-Expression: BSD-3-Clause
8
8
  Project-URL: Homepage, https://github.com/diffpy/diffpy.apps/
9
9
  Project-URL: Issues, https://github.com/diffpy/diffpy.apps/issues/
@@ -28,7 +28,7 @@ pytestmark = pytest.mark.skipif(
28
28
  update=False,
29
29
  ),
30
30
  "cwd",
31
- ".claude/skills/cmi-skill",
31
+ ".claude/skills/diffpy-playbook",
32
32
  ),
33
33
  # C2: diffpy.apps agentify --system
34
34
  # Deploys system claude skill.
@@ -40,7 +40,7 @@ pytestmark = pytest.mark.skipif(
40
40
  update=False,
41
41
  ),
42
42
  "home",
43
- ".claude/skills/cmi-skill",
43
+ ".claude/skills/diffpy-playbook",
44
44
  ),
45
45
  # C3: diffpy.apps agentify --agent codex
46
46
  # Deploys workspace codex skill.
@@ -52,7 +52,7 @@ pytestmark = pytest.mark.skipif(
52
52
  update=False,
53
53
  ),
54
54
  "cwd",
55
- ".codex/skills/cmi-skill",
55
+ ".codex/skills/diffpy-playbook",
56
56
  ),
57
57
  # C4: diffpy.apps agentify --agent codex --system
58
58
  # Deploys system codex skill.
@@ -64,7 +64,7 @@ pytestmark = pytest.mark.skipif(
64
64
  update=False,
65
65
  ),
66
66
  "home",
67
- ".codex/skills/cmi-skill",
67
+ ".codex/skills/diffpy-playbook",
68
68
  ),
69
69
  ],
70
70
  )
@@ -94,14 +94,17 @@ def test_agentify_update():
94
94
  update=False,
95
95
  )
96
96
  agentify(args)
97
- skill_path = Path(tmp) / "cwd" / ".claude" / "skills" / "cmi-skill"
97
+ skill_path = (
98
+ Path(tmp) / "cwd" / ".claude" / "skills" / "diffpy-playbook"
99
+ )
98
100
  assert skill_path.exists()
99
101
  args.update = True
100
102
  agentify(args)
101
103
  pytest.raises(
102
104
  FileExistsError,
103
105
  match=re.escape(
104
- f"Agentic skill cmi-skill already exists at {skill_path}. "
106
+ "Agentic skill diffpy-playbook already exists at "
107
+ f"{skill_path}. "
105
108
  "To overwrite, pass '--update' flag to update the skill"
106
109
  ),
107
110
  )
File without changes