chemparseplot 1.6.0__py3-none-any.whl → 1.7.0__py3-none-any.whl

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.
_version.py CHANGED
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.6.0'
22
- __version_tuple__ = version_tuple = (1, 6, 0)
21
+ __version__ = version = '1.7.0'
22
+ __version_tuple__ = version_tuple = (1, 7, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
chemparseplot/__init__.py CHANGED
@@ -3,3 +3,5 @@
3
3
  # SPDX-License-Identifier: MIT
4
4
 
5
5
  from chemparseplot import parse, units
6
+
7
+ __all__ = ["parse", "units"]
@@ -4,6 +4,8 @@
4
4
 
5
5
  from chemparseplot.parse import eon, orca, patterns
6
6
 
7
+ __all__ = ["eon", "orca", "patterns"]
8
+
7
9
  # Lazy imports for modules with optional heavy deps (h5py, pandas)
8
10
  # Import directly: from chemparseplot.parse.chemgp_hdf5 import read_h5_table
9
11
  # Or: from chemparseplot.parse import plumed, projection
@@ -140,7 +140,9 @@ def load_dimer_trajectory(job_dir: Path) -> DimerTrajectoryData:
140
140
  initial = atoms_list[0]
141
141
 
142
142
  saddle_path = job_dir / "saddle.con"
143
- saddle = readcon.read_con_as_ase(str(saddle_path))[0] if saddle_path.exists() else None
143
+ saddle = (
144
+ readcon.read_con_as_ase(str(saddle_path))[0] if saddle_path.exists() else None
145
+ )
144
146
 
145
147
  mode = _load_mode_dat(job_dir / "mode.dat")
146
148
 
@@ -7,10 +7,15 @@ from enum import Enum
7
7
  from pathlib import Path
8
8
 
9
9
  import numpy as np
10
- from rgpycrumbs.basetypes import DimerOpt, MolGeom, SaddleMeasure, SpinID
11
- from rgpycrumbs.parsers.bless import BLESS_LOG
12
- from rgpycrumbs.parsers.common import _NUM
13
- from rgpycrumbs.search.helpers import tail
10
+
11
+ try:
12
+ from rgpycrumbs.basetypes import DimerOpt, MolGeom, SaddleMeasure, SpinID
13
+ from rgpycrumbs.parsers.bless import BLESS_LOG
14
+ from rgpycrumbs.parsers.common import _NUM
15
+ from rgpycrumbs.search.helpers import tail
16
+ except ImportError:
17
+ DimerOpt = MolGeom = SaddleMeasure = SpinID = None
18
+ BLESS_LOG = _NUM = tail = None
14
19
 
15
20
  log = logging.getLogger(__name__)
16
21
 
@@ -3,3 +3,5 @@
3
3
  # SPDX-License-Identifier: MIT
4
4
 
5
5
  from chemparseplot.parse.orca import geomscan
6
+
7
+ __all__ = ["geomscan"]
@@ -17,8 +17,6 @@ end
17
17
 
18
18
  import re
19
19
 
20
- from rgpycrumbs.basetypes import nebiter, nebpath
21
-
22
20
  import chemparseplot.parse.converter as conv
23
21
  import chemparseplot.parse.patterns as pat
24
22
  from chemparseplot.units import Q_
@@ -38,6 +36,8 @@ def extract_interp_points(text: str) -> list[int, Q_, Q_]:
38
36
  ```{versionadded} 0.0.2
39
37
  ```
40
38
  """
39
+ from rgpycrumbs.basetypes import nebiter, nebpath
40
+
41
41
  data = []
42
42
  for match in re.finditer(INTERP_PAT, text, re.DOTALL):
43
43
  iteration = int(match.group("iteration"))
@@ -17,7 +17,6 @@ from pathlib import Path
17
17
  from typing import Any
18
18
 
19
19
  import numpy as np
20
- from rgpycrumbs._aux import ensure_import
21
20
 
22
21
  # Lazy import - will be loaded on first use
23
22
  _opi_output = None
@@ -27,6 +26,8 @@ def _get_opi_output():
27
26
  """Get OPI Output class, installing if needed."""
28
27
  global _opi_output
29
28
  if _opi_output is None:
29
+ from rgpycrumbs._aux import ensure_import
30
+
30
31
  _opi_output = ensure_import("opi.output.core").Output
31
32
  return _opi_output
32
33
 
@@ -8,8 +8,13 @@ from pathlib import Path
8
8
  import ase
9
9
  import numpy as np
10
10
  from ase.io import read
11
- from rgpycrumbs.basetypes import SaddleMeasure, SpinID
12
- from rgpycrumbs.time.helpers import one_day_tdelta
11
+
12
+ try:
13
+ from rgpycrumbs.basetypes import SaddleMeasure, SpinID
14
+ from rgpycrumbs.time.helpers import one_day_tdelta
15
+ except ImportError:
16
+ SaddleMeasure = SpinID = None
17
+ one_day_tdelta = None
13
18
 
14
19
  log = logging.getLogger(__name__)
15
20
 
@@ -3,3 +3,5 @@
3
3
  # SPDX-License-Identifier: MIT
4
4
 
5
5
  from chemparseplot.parse.trajectory import hdf5, neb
6
+
7
+ __all__ = ["hdf5", "neb"]
@@ -11,6 +11,15 @@ from chemparseplot.plot.theme import (
11
11
  setup_publication_theme,
12
12
  )
13
13
 
14
+ __all__ = [
15
+ "RUHI_COLORS",
16
+ "RUHI_THEME",
17
+ "PlotTheme",
18
+ "get_theme",
19
+ "setup_global_theme",
20
+ "setup_publication_theme",
21
+ ]
22
+
14
23
 
15
24
  # Lazy imports for submodules with heavy deps (cmcrameri, pint, etc.)
16
25
  def __getattr__(name):
@@ -1,5 +1,3 @@
1
- from functools import lru_cache
2
-
3
1
  """ChemGP visualization functions.
4
2
 
5
3
  Mixed plotnine (for 1D line charts) and matplotlib (for 2D
@@ -15,6 +13,7 @@ for ggplot2 grammar.
15
13
  """
16
14
 
17
15
  import logging
16
+ from functools import lru_cache
18
17
 
19
18
  import matplotlib.patheffects as mpe
20
19
  import matplotlib.pyplot as plt
@@ -1,7 +1,6 @@
1
1
  from typing import Any
2
2
 
3
3
  import matplotlib.pyplot as plt
4
- from rgpycrumbs.interpolation import spline_interp
5
4
 
6
5
  from chemparseplot.plot.structs import BasePlotter
7
6
 
@@ -24,6 +23,8 @@ def plot_energy_paths(
24
23
  distance_values = path.distance.to(units["distance"])
25
24
  energy_values = path.energy.to(units["energy"])
26
25
 
26
+ from rgpycrumbs.interpolation import spline_interp
27
+
27
28
  distance_fine, energy_fine = spline_interp(distance_values.m, energy_values.m)
28
29
 
29
30
  # Determine the color for each path using the colormap
chemparseplot/plot/neb.py CHANGED
@@ -8,7 +8,6 @@ from dataclasses import dataclass
8
8
  from pathlib import Path
9
9
  from typing import Any
10
10
 
11
- import matplotlib.patheffects as path_effects
12
11
  import matplotlib.pyplot as plt
13
12
  import numpy as np
14
13
  from ase.io import write as ase_write
@@ -16,12 +15,6 @@ from matplotlib import tri
16
15
  from matplotlib.collections import LineCollection
17
16
  from matplotlib.offsetbox import AnnotationBbox, OffsetImage
18
17
  from matplotlib.patches import ArrowStyle
19
- from rgpycrumbs.surfaces import (
20
- NYSTROM_N_INDUCING_DEFAULT,
21
- NYSTROM_THRESHOLD,
22
- get_surface_model,
23
- nystrom_paths_needed,
24
- )
25
18
  from scipy import ndimage
26
19
  from scipy.interpolate import (
27
20
  CubicHermiteSpline,
@@ -813,6 +806,13 @@ def plot_landscape_surface(
813
806
  Added the *project_path* parameter for reaction-valley coordinate projection.
814
807
  ```
815
808
  """
809
+ from rgpycrumbs.surfaces import (
810
+ NYSTROM_N_INDUCING_DEFAULT,
811
+ NYSTROM_THRESHOLD,
812
+ get_surface_model,
813
+ nystrom_paths_needed,
814
+ )
815
+
816
816
  log.info(f"Generating 2D surface using {method} (Projected: {project_path})...")
817
817
 
818
818
  if basis is None and project_path:
@@ -2,7 +2,6 @@ from collections import namedtuple
2
2
 
3
3
  import matplotlib.pyplot as plt
4
4
  from cmcrameri import cm
5
- from rgpycrumbs.interpolation import spline_interp
6
5
 
7
6
  # Define a namedtuple for energy paths
8
7
  EnergyPath = namedtuple("EnergyPath", ["label", "distance", "energy"])
@@ -77,6 +76,8 @@ class TwoDimPlot(BasePlotter):
77
76
  for idx, xy_data in enumerate(self.data):
78
77
  x_values = xy_data.x.to(self.x_unit).m
79
78
  y_values = xy_data.y.to(self.y_unit).m
79
+ from rgpycrumbs.interpolation import spline_interp
80
+
80
81
  distance_fine, y_fine = spline_interp(x_values, y_values)
81
82
 
82
83
  color = self.colormap(idx / len(self.data))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chemparseplot
3
- Version: 1.6.0
3
+ Version: 1.7.0
4
4
  Summary: Parsers and plotting tools for computational chemistry
5
5
  Project-URL: Documentation, https://chemparseplot.rgoswami.me
6
6
  Project-URL: Issues, https://github.com/HaoZeke/chemparseplot/issues
@@ -1,8 +1,8 @@
1
- _version.py,sha256=1J23hr68olyCiSnbHNYm6VGnkzB4hDCEmJzkxBTNSWo,520
2
- chemparseplot/__init__.py,sha256=U07NlVOSl9tGXtOiQK1cIf-gb7OR_sTSQB8UykcvqGk,140
1
+ _version.py,sha256=pvN114lCpRNcdz9ufJCnl1MMqgOtZU1RmZfWI_uxL9s,520
2
+ chemparseplot/__init__.py,sha256=Tvnz_cGS0V_dJ-np-YpbKFIT68BB3pRLFMi1MOeLGrs,170
3
3
  chemparseplot/units.py,sha256=YEZgYIIruRfpc8eF9u69BRMMLA4sZFyQPk2-alT3Cmg,438
4
4
  chemparseplot/util.py,sha256=iGVwY4gG99llnF7yttoO4lQSkgsHiHV8ubc-5CrGhss,4350
5
- chemparseplot/parse/__init__.py,sha256=stzdzTvI2m-THRpI3KhFy3_eXPLglCygajM59Zxpzq8,355
5
+ chemparseplot/parse/__init__.py,sha256=Hz8nc6r1A0P47wxXSkHpbkhgE1HfG3NJL9Pkk7Qkv-0,394
6
6
  chemparseplot/parse/chemgp_hdf5.py,sha256=wnmS-9xoHBZISPGwPzpNG9rLtCu_g6PMflaVr2zFkts,4022
7
7
  chemparseplot/parse/chemgp_jsonl.py,sha256=tzxVvvQTCNOSVm89AjNRYE8MYWO1Sz5t3RBMUQIXMOw,9319
8
8
  chemparseplot/parse/converter.py,sha256=yASb3q8gU4kxMm7G2mRMJpbCTh-uJdonRBsEYoQYUts,354
@@ -12,32 +12,32 @@ chemparseplot/parse/patterns.py,sha256=rVP2-CDoDPR4SGSu85x8WiEgAVX1vudT879cmsHlT
12
12
  chemparseplot/parse/plumed.py,sha256=9K6mIa537TGONyqfP65pCm-u4HAEQQ3ZzGepk7CZ4HE,15847
13
13
  chemparseplot/parse/projection.py,sha256=NrfLiHe31r9jF7LmHS-E_TgflRodwBlvq60ledgw1YE,3739
14
14
  chemparseplot/parse/eon/__init__.py,sha256=rKIpxGHKDdcaevWZtjAatCfDsdNfg4y5MXRfJqBBDb8,30
15
- chemparseplot/parse/eon/dimer_trajectory.py,sha256=FS-SSWFuL9RpIAbMEG_IyQ4sLxo5Xa-spkgNVUXBSNY,4245
15
+ chemparseplot/parse/eon/dimer_trajectory.py,sha256=kz9uh0Bt72KItV9A6eYVJPE25369l3FanFQZVFWAXJs,4261
16
16
  chemparseplot/parse/eon/gprd.py,sha256=oAXWgrD1_wejCwCFOMUaruRylyemqBnf_wchbz267ec,12411
17
17
  chemparseplot/parse/eon/min_trajectory.py,sha256=GonXo82ZCnM9ycxFRhlvztEJkc4G9yxS6kvfLklCASI,3369
18
18
  chemparseplot/parse/eon/minimization.py,sha256=TswHBgYussFt0Cv6WQF02A0AKOXni7IvpTSjSPCS7ug,767
19
19
  chemparseplot/parse/eon/neb.py,sha256=8ynn7w5wv_FXMyLwhT1ghJswhe70sOnpk8mFGlPxv-E,11896
20
- chemparseplot/parse/eon/saddle_search.py,sha256=q2Oief5CGJtUstXKg47ZIMOd8tGZF-XcJK22aEAgxYo,11759
21
- chemparseplot/parse/orca/__init__.py,sha256=c3EdTDCGzd0UsJC-aj0l17X8TV9VYEzOOox-oNnc3N8,147
20
+ chemparseplot/parse/eon/saddle_search.py,sha256=uLa5UbEV4Dj4H60fIXvEf44FwkpKFR2-47Qi3p2WqY4,11891
21
+ chemparseplot/parse/orca/__init__.py,sha256=Iui-iuRSA_GhdByi0FdoCJj42_hPzuPrG24qVOni6dQ,171
22
22
  chemparseplot/parse/orca/geomscan.py,sha256=0OuUObmkJOtLJFwkMu_fzEUhF64qojGpZB5SUAjYseY,1950
23
23
  chemparseplot/parse/orca/neb/__init__.py,sha256=bddiBqS91BWyW7IQeXMHRAnzKdERQRwXCQBJcDFuuto,556
24
- chemparseplot/parse/orca/neb/interp.py,sha256=pyQdNR1is3gCrnCtIZYH6BMOhwiB_chr5O__vulC9U4,1377
25
- chemparseplot/parse/orca/neb/opi_parser.py,sha256=9XEy5_C8E_feb05NJGHc0mOYrgcBdysvuH74HLooDgs,7466
26
- chemparseplot/parse/sella/saddle_search.py,sha256=W4aX17UMQJa27ana2VApwTUG2wcKqfJEsz8PysoyrTE,7918
27
- chemparseplot/parse/trajectory/__init__.py,sha256=JiSZ4kTcHGAWUk-k-vqTksZQIePiTGexdw-aMxBr3R8,154
24
+ chemparseplot/parse/orca/neb/interp.py,sha256=dl6bpxNZbQ1jzXTp0NWDkKBFnAeh6xkt8qZBLB-DLU8,1381
25
+ chemparseplot/parse/orca/neb/opi_parser.py,sha256=BSIDZmMojGM8kKGZ6fQEs9wdO0L27WS4cmIwpkYmHdY,7475
26
+ chemparseplot/parse/sella/saddle_search.py,sha256=Jh0tH7r4tCiNeyCrpyHmhUVuspf_n6MaZ5_p-Gq2SOw,8012
27
+ chemparseplot/parse/trajectory/__init__.py,sha256=b04xOTVJWRZZk5bwwuk9DmHAE75pB56fA30_BlwUffM,181
28
28
  chemparseplot/parse/trajectory/hdf5.py,sha256=c3Q3wZan6hG_PVNpf1sYkgxYCd66aSdd0NZTInNlqzQ,8522
29
29
  chemparseplot/parse/trajectory/neb.py,sha256=9JuGtMq6p3IYLewIhlUL2vWh4lYRmCau_YpI0echy6s,5973
30
- chemparseplot/plot/__init__.py,sha256=htxoJAG6OhpUbJZ4bUod8XlZlHG8GiVBC4D80kp_twY,803
31
- chemparseplot/plot/chemgp.py,sha256=3WgB-SP2J0GGJK5-tlvMW4ClXj3nl87oE7XuYQjnog0,37461
32
- chemparseplot/plot/geomscan.py,sha256=okAySDYthm8c35WN8noCgywKLlNKUBwEemK1uCYMXi8,1558
33
- chemparseplot/plot/neb.py,sha256=o1mp4FE0SJeA53t1p7Acp1l-tIYRGblO_rs_JjidK1I,47916
30
+ chemparseplot/plot/__init__.py,sha256=3u02ig8DBXHKtNFH_3W0nMl7r5ogHoqiDvnFmm9PdnE,946
31
+ chemparseplot/plot/chemgp.py,sha256=V0NBfrCiNdlwUZ3fXx1Q6tuh-cIgBm91vO8KwvhKt08,37460
32
+ chemparseplot/plot/geomscan.py,sha256=DnjzssVtiwNPlhXlYHT6Rt5E1vs5ma_F64Go87F9CqE,1567
33
+ chemparseplot/plot/neb.py,sha256=HgHc9iG-VrP22Gzl4iTrnmq2S781BWahycqYMOxDio0,47895
34
34
  chemparseplot/plot/optimization.py,sha256=tYHmdAIv84eZ2l8I7oXdcUH9lCWFjSbBn3mwBTYuHGU,6499
35
35
  chemparseplot/plot/plumed.py,sha256=-TJsB_ughlXtjj7dI-yOH9uzcBypMFWyr_z0V2LYo40,3883
36
- chemparseplot/plot/structs.py,sha256=rDf5rsgA0js5zun1YPYrSNoDGP-qKgN828i0S88V3Dc,3231
36
+ chemparseplot/plot/structs.py,sha256=PNWGj8xkZ9JsH6IRBCm6uiWK7cCCHomXSCVBLcUUWwc,3244
37
37
  chemparseplot/plot/theme.py,sha256=UIN4RpKz7ZSqsXiwcdSHfpi4qw1C5Hm65hzEt8yikTw,5041
38
- tests/conftest.py,sha256=VMtKzA-vBPyxzdXrPnLz1r7pm1qbAUEPeyq_K1J6bVA,886
39
- tests/test_coverage_batch.py,sha256=tMjbp953aPW051N0sE5jcBadhZlSbNrq_cJei5it1b4,15502
40
- tests/test_full_coverage.py,sha256=rYv3OOGcSE5u1tjSimdaAqpr08i6o92xpDr2H39bu0o,59256
38
+ tests/conftest.py,sha256=DEqQfzjQIi6YZA-4vmjtnwDJ46dQqP_r88ncIsHfjH4,900
39
+ tests/test_coverage_batch.py,sha256=22WeLuZkq5wji7AeURVdGpbs-DLIxIM-zHZODsim7_E,15616
40
+ tests/test_full_coverage.py,sha256=mS6RF0nECYs1_xGTSh-oFo3GEX2bIoOV8m6lqp_OswU,59506
41
41
  tests/parse/test_chemgp_hdf5.py,sha256=Sf7677fV1xLvTCawxQTuJ2hVi1aQQbRP_nk7BQ0WG1k,4309
42
42
  tests/parse/test_converter.py,sha256=yRaaggSOpGK2TvLhhPz5PJzOBACvkOG1BhJGPkQKDaA,798
43
43
  tests/parse/test_dimer_trajectory.py,sha256=JHcLdAZuGETPLDaSla601n4Q352UcU7efyxbHPkEJ94,5643
@@ -49,15 +49,15 @@ tests/parse/test_projection.py,sha256=vp_OMKiKwgHf88xqMgoJetpHz4Qm-0pH_UtaHKwve0
49
49
  tests/parse/test_trajectory_hdf5.py,sha256=NQSIhv9YUEW1HnQN4rRFglvUZBF-VrtJqKY4pyf54XI,10845
50
50
  tests/parse/test_trajectory_neb.py,sha256=qSg7YIpzrP3yykHk0EglB8J-Dtxb5pdALoLiT-ztEXI,8987
51
51
  tests/parse/orca/test_geomscan.py,sha256=JIpgRa7-XTAh9xiq0GvGDn4dsFXW1EAx0sqPgSiNyY4,1796
52
- tests/parse/orca/test_interp.py,sha256=ho03AeB6incdr4_a19OT50vw4SqQ_EdMszNs1dHXIL4,1625
52
+ tests/parse/orca/test_interp.py,sha256=mG5cBZRPK5f7P562hTe07UnXVHSeZVvTteI-4KBjJSc,1738
53
53
  tests/plot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  tests/plot/test_chemgp_utils.py,sha256=NKdWTOQVkK_Zln1kXSx2iavVQwa2JUyTZqzkAIhKVuI,1775
55
55
  tests/plot/test_neb_renderers.py,sha256=fe6Z4jL1rwoxqh3jpx1qhls63tic-2CNDqAbAw1cvPw,2364
56
56
  tests/plot/test_optimization.py,sha256=hgAToLPFqQyElbrf1j_7qXU4mvMYVqhH9JKXAKUUAHY,6366
57
57
  tests/plot/test_projection_refactor.py,sha256=O0iydKG4qfVfIv7cLsTYkZOjKLOZrlGCkIe7yVJ7QJw,4954
58
58
  tests/plot/test_strip_rendering.py,sha256=ebyX0juQNzD5xnPmPvFapqmZrgj7vZiuHBt-rx-0yD0,5659
59
- tests/tutorials/test_chemparseplot.py,sha256=iedDw1qXR_ETwnqj6fqbXeNOsDx5IRhGgShsoFSsrwU,4262
60
- chemparseplot-1.6.0.dist-info/METADATA,sha256=FhxsJAoBPen_mqnlYmpK5eNq5JO7dWZRdw3EMKOaZRs,7682
61
- chemparseplot-1.6.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
62
- chemparseplot-1.6.0.dist-info/licenses/LICENSE,sha256=WpBevJdirrfildX-iO61fdIm4hJ0EQniBoxNJJPlFl0,1127
63
- chemparseplot-1.6.0.dist-info/RECORD,,
59
+ tests/tutorials/test_chemparseplot.py,sha256=vndGmIn6Hu7vjf-_Fl3Uj0uAYp5JAnypgCWbBKataLE,4345
60
+ chemparseplot-1.7.0.dist-info/METADATA,sha256=NURX2W5khchi-y4D5QhNovpfkPPzQEeo5XRUk_kTKIc,7682
61
+ chemparseplot-1.7.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
62
+ chemparseplot-1.7.0.dist-info/licenses/LICENSE,sha256=WpBevJdirrfildX-iO61fdIm4hJ0EQniBoxNJJPlFl0,1127
63
+ chemparseplot-1.7.0.dist-info/RECORD,,
tests/conftest.py CHANGED
@@ -8,7 +8,7 @@ import pytest
8
8
  # Define the requirements for each suite/marker
9
9
  ENVIRONMENT_REQUIREMENTS = {
10
10
  "pure": ["numpy"],
11
- "neb": ["numpy", "polars", "ase", "h5py", "scipy", "matplotlib"],
11
+ "neb": ["numpy", "polars", "ase", "h5py", "scipy", "matplotlib", "rgpycrumbs"],
12
12
  }
13
13
 
14
14
 
@@ -1,11 +1,19 @@
1
1
  # SPDX-FileCopyrightText: 2023-present Rohit Goswami <rog32@hi.is>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
+ import pytest
5
+
6
+ from tests.conftest import skip_if_not_env
7
+
8
+ skip_if_not_env("neb")
9
+
4
10
  from rgpycrumbs.basetypes import nebiter
5
11
 
6
12
  from chemparseplot.parse.orca.neb.interp import extract_interp_points
7
13
  from chemparseplot.units import ureg
8
14
 
15
+ pytestmark = pytest.mark.neb
16
+
9
17
 
10
18
  def test_extract_interp_points_valid_input():
11
19
  # Example valid text input
@@ -191,6 +191,10 @@ class TestPlotLazyImports:
191
191
  # ============================================================
192
192
  # chemparseplot.parse.neb_utils (calculate_landscape_coords)
193
193
  # ============================================================
194
+ @pytest.mark.skipif(
195
+ importlib.util.find_spec("rgpycrumbs") is None,
196
+ reason="rgpycrumbs not installed",
197
+ )
194
198
  class TestCalculateLandscapeCoords:
195
199
  def test_with_mock_ira(self):
196
200
  """Test with a mock IRA that returns identity RMSD."""
@@ -32,6 +32,8 @@ try:
32
32
  except ImportError:
33
33
  _HAS_CMCRAMERI = False
34
34
 
35
+ _HAS_RGPYCRUMBS = importlib.util.find_spec("rgpycrumbs") is not None
36
+
35
37
 
36
38
  # ============================================================
37
39
  # chemparseplot.parse.chemgp_hdf5
@@ -773,7 +775,8 @@ _PY310 = sys.version_info < (3, 11)
773
775
 
774
776
 
775
777
  @pytest.mark.skipif(
776
- not _HAS_CMCRAMERI or _PY310, reason="cmcrameri required, py3.10 has recursion issue"
778
+ not _HAS_CMCRAMERI or _PY310 or not _HAS_RGPYCRUMBS,
779
+ reason="cmcrameri + rgpycrumbs required, py3.10 has recursion issue",
777
780
  )
778
781
  class TestGeomscanPlot:
779
782
  def test_plot_energy_paths(self):
@@ -794,7 +797,7 @@ class TestGeomscanPlot:
794
797
  units = {"distance": "angstrom", "energy": "eV"}
795
798
 
796
799
  with patch(
797
- "chemparseplot.plot.geomscan.spline_interp",
800
+ "rgpycrumbs.interpolation.spline_interp",
798
801
  return_value=(np.linspace(0, 3, 100), np.sin(np.linspace(0, 3, 100))),
799
802
  ):
800
803
  from chemparseplot.plot.geomscan import plot_energy_paths
@@ -1274,6 +1277,7 @@ class TestNebPlotSurface:
1274
1277
  # ============================================================
1275
1278
  # chemparseplot.parse.trajectory.hdf5 (lines 253-294)
1276
1279
  # ============================================================
1280
+ @pytest.mark.skipif(not _HAS_RGPYCRUMBS, reason="rgpycrumbs required")
1277
1281
  class TestTrajectoryHdf5:
1278
1282
  def _make_h5_result(self, tmp_path, n_images=5, n_atoms=3):
1279
1283
  """Create a minimal neb_result.h5 file."""
@@ -1414,6 +1418,7 @@ class TestTrajectoryHdf5:
1414
1418
  # ============================================================
1415
1419
  # chemparseplot.parse.trajectory.neb (fallback paths)
1416
1420
  # ============================================================
1421
+ @pytest.mark.skipif(not _HAS_RGPYCRUMBS, reason="rgpycrumbs required")
1417
1422
  class TestTrajectoryNeb:
1418
1423
  def test_get_energy_from_calc(self):
1419
1424
  from ase import Atoms
@@ -6,6 +6,12 @@ Verifies that tutorial code examples work correctly.
6
6
  Run with: cd chemparseplot && uv run python tests/tutorials/test_chemparseplot.py
7
7
  """
8
8
 
9
+ import pytest
10
+
11
+ from tests.conftest import skip_if_not_env
12
+
13
+ skip_if_not_env("neb")
14
+
9
15
  import sys
10
16
  from pathlib import Path
11
17