Skip to content

Commit 58efcba

Browse files
version 0.3.15
1 parent 9d54745 commit 58efcba

14 files changed

Lines changed: 563 additions & 311 deletions

File tree

.github/workflows/tests.yml

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,28 @@ on:
55
branches: ["main"]
66
pull_request:
77
branches: ["main"]
8+
schedule:
9+
- cron: "17 3 * * *"
10+
workflow_dispatch:
11+
inputs:
12+
python-version:
13+
description: "Python version for the full integration job"
14+
required: false
15+
default: "3.12"
16+
type: string
17+
pytest-args:
18+
description: "pytest arguments for the full integration job"
19+
required: false
20+
default: "-q -o addopts="
21+
type: string
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.ref }}
25+
cancel-in-progress: true
826

927
jobs:
10-
test:
28+
fast-tests:
29+
name: fast tests (${{ matrix.python-version }})
1130
runs-on: ubuntu-latest
1231

1332
strategy:
@@ -42,6 +61,42 @@ jobs:
4261
python -m pip --version
4362
python -m pip freeze | sed -n '1,200p'
4463
45-
- name: Run tests
64+
- name: Run fast tests
4665
run: |
4766
pytest -q
67+
68+
full-tests:
69+
name: full integration tests
70+
runs-on: ubuntu-latest
71+
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
72+
73+
env:
74+
PYTHONUTF8: "1"
75+
76+
steps:
77+
- name: Checkout repository
78+
uses: actions/checkout@v4
79+
80+
- name: Set up Python
81+
uses: actions/setup-python@v5
82+
with:
83+
python-version: ${{ inputs['python-version'] || '3.12' }}
84+
cache: "pip"
85+
cache-dependency-path: |
86+
pyproject.toml
87+
88+
- name: Install package + test deps
89+
run: |
90+
python -m pip install --upgrade pip
91+
python -m pip install -e ".[dev]"
92+
python -m pip install pyscf
93+
94+
- name: Debug environment
95+
run: |
96+
python --version
97+
python -m pip --version
98+
python -m pip freeze | sed -n '1,200p'
99+
100+
- name: Run full test suite
101+
run: |
102+
pytest ${{ inputs['pytest-args'] || '-q -o addopts=' }}

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ All notable changes to this project will be documented in this file.
66

77
## [Unreleased]
88

9+
No unreleased changes.
10+
11+
---
12+
13+
## [0.3.25] - April 21, 2026
14+
915
### Changed
1016

1117
- **Faster default pytest target**
@@ -14,6 +20,29 @@ All notable changes to this project will be documented in this file.
1420
`pytest -q` runs the fast development suite by default. The full integration
1521
suite remains available with `pytest -q -o addopts=''`.
1622

23+
- **Split fast and full test CI**
24+
25+
Updated the tests workflow so pull requests and pushes run the fast pytest
26+
matrix, while the full integration suite runs on a scheduled/manual Python
27+
3.12 job.
28+
29+
- **Lightweight CLI help startup**
30+
31+
Made package and CLI public-entrypoint imports lazy so `python -m vqe --help`,
32+
`python -m qpe --help`, and `python -m qite --help` avoid importing the
33+
PennyLane/OpenFermion stack until a command actually runs.
34+
35+
- **Shared lazy public API exports**
36+
37+
Added a small shared lazy-export helper and used it across `common`, `vqe`,
38+
`qpe`, and `qite` so public imports remain stable without duplicating
39+
package-level `__getattr__` boilerplate.
40+
41+
- **Slimmer fast excited-state smoke coverage**
42+
43+
Split EOM-VQE and EOM-QSE fast tests into single-run smoke checks while
44+
keeping the more expensive deterministic rerun checks in the full slow suite.
45+
1746
- **Tightened public API reference**
1847

1948
Reworked the Sphinx API reference into task-oriented sections for primary

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,8 @@ Variational_Quantum_Eigensolver/
401401

402402
## Testing
403403

404-
The default pytest target is the fast development suite. Slow chemistry and
405-
subprocess CLI integration tests are marked separately.
404+
The default pytest target is the fast development suite. Slow chemistry checks
405+
and selected subprocess CLI integration tests are marked separately.
406406

407407
```bash
408408
pytest -q

USAGE.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -850,8 +850,9 @@ qite run-qrte --force
850850

851851
## Testing
852852

853-
The default pytest target runs the fast development suite. Slow chemistry and
854-
subprocess CLI integration tests are available behind pytest markers.
853+
The default pytest target runs the fast development suite. Slow chemistry
854+
checks and selected subprocess CLI integration tests are available behind
855+
pytest markers.
855856

856857
```bash
857858
pytest -q

common/__init__.py

Lines changed: 56 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,93 +4,79 @@
44
55
Shared utilities used across VQE, QPE, and future solvers.
66
7-
This subpackage contains:
8-
• common.molecules — canonical molecule registry
9-
• common.geometry — unified geometry generators (bond/angle scans)
10-
• common.hamiltonian — single source of truth for Hamiltonian construction
11-
• common.plotting — global plotting + filename/dir management
12-
13-
All high-level solvers (VQE, QPE, QSVT, etc.) should import molecule
14-
definitions, geometry logic, Hamiltonians, and plotting helpers from here
15-
to avoid duplication and ensure reproducibility.
7+
The public exports are resolved lazily so importing high-level packages for
8+
metadata or CLI help does not also import the quantum chemistry stack.
169
"""
1710

1811
from __future__ import annotations
1912

2013
from importlib.metadata import PackageNotFoundError, version as _pkg_version
14+
from typing import Any
2115

2216
from . import mpl_env as _mpl_env # noqa: F401
17+
from .lazy import LazyExports, list_exports, load_export
2318

2419
try:
2520
__version__ = _pkg_version("vqe-pennylane")
2621
except PackageNotFoundError: # pragma: no cover
2722
__version__ = "0.0.0"
2823

2924

30-
# Molecule data + helpers
31-
from .molecules import MOLECULES, get_molecule_config # noqa: F401, E402
32-
33-
# Geometry (bond length, angle scans, parametrized coordinates)
34-
from .geometry import generate_geometry # noqa: F401, E402
35-
36-
# Hamiltonian construction (PennyLane + OpenFermion fallback)
37-
from .hamiltonian import ( # noqa: F401, E402
38-
build_hamiltonian,
39-
get_exact_spectrum,
40-
summarize_registry_coverage,
41-
)
42-
from .benchmarks import ( # noqa: F401, E402
43-
analyze_qpe_result,
44-
exact_ground_energy_for_problem,
45-
ionization_energy_panel,
46-
qpe_branch_candidates,
47-
qpe_calibration_plan,
48-
summarize_problem,
49-
summary_stats,
50-
timed_call,
51-
)
52-
from .metrics import compute_fidelity # noqa: F401, E402
53-
from .problem import ResolvedProblem, resolve_problem # noqa: F401, E402
54-
55-
# Molecule visualization
56-
from .molecule_viz import (
57-
plot_molecule,
58-
infer_bonds,
59-
infer_angles_from_bonds,
60-
) # noqa: F401, E402
61-
62-
# Plotting utilities shared across VQE + QPE
63-
from .plotting import build_filename, save_plot # noqa: F401, E402
64-
from .naming import format_molecule_name, format_token # noqa: F401, E402
65-
66-
__all__ = [
25+
_EXPORTS: LazyExports = {
6726
# Molecules
68-
"MOLECULES",
69-
"get_molecule_config",
27+
"MOLECULES": ("common.molecules", "MOLECULES"),
28+
"get_molecule_config": ("common.molecules", "get_molecule_config"),
7029
# Geometry
71-
"generate_geometry",
30+
"generate_geometry": ("common.geometry", "generate_geometry"),
7231
# Hamiltonian
73-
"build_hamiltonian",
74-
"get_exact_spectrum",
75-
"summarize_registry_coverage",
76-
"timed_call",
77-
"summary_stats",
78-
"qpe_branch_candidates",
79-
"analyze_qpe_result",
80-
"qpe_calibration_plan",
81-
"exact_ground_energy_for_problem",
82-
"ionization_energy_panel",
83-
"summarize_problem",
84-
"compute_fidelity",
85-
"ResolvedProblem",
86-
"resolve_problem",
32+
"build_hamiltonian": ("common.hamiltonian", "build_hamiltonian"),
33+
"get_exact_spectrum": ("common.hamiltonian", "get_exact_spectrum"),
34+
"summarize_registry_coverage": (
35+
"common.hamiltonian",
36+
"summarize_registry_coverage",
37+
),
38+
# Benchmarks/helpers
39+
"timed_call": ("common.benchmarks", "timed_call"),
40+
"summary_stats": ("common.benchmarks", "summary_stats"),
41+
"qpe_branch_candidates": ("common.benchmarks", "qpe_branch_candidates"),
42+
"analyze_qpe_result": ("common.benchmarks", "analyze_qpe_result"),
43+
"qpe_calibration_plan": ("common.benchmarks", "qpe_calibration_plan"),
44+
"exact_ground_energy_for_problem": (
45+
"common.benchmarks",
46+
"exact_ground_energy_for_problem",
47+
),
48+
"ionization_energy_panel": ("common.benchmarks", "ionization_energy_panel"),
49+
"summarize_problem": ("common.benchmarks", "summarize_problem"),
50+
"compute_fidelity": ("common.metrics", "compute_fidelity"),
51+
"ResolvedProblem": ("common.problem", "ResolvedProblem"),
52+
"resolve_problem": ("common.problem", "resolve_problem"),
8753
# Plotting
88-
"build_filename",
89-
"save_plot",
90-
"format_molecule_name",
91-
"format_token",
54+
"build_filename": ("common.plotting", "build_filename"),
55+
"save_plot": ("common.plotting", "save_plot"),
56+
"format_molecule_name": ("common.naming", "format_molecule_name"),
57+
"format_token": ("common.naming", "format_token"),
9258
# Molecule visualization
93-
"plot_molecule",
94-
"infer_bonds",
95-
"infer_angles_from_bonds",
59+
"plot_molecule": ("common.molecule_viz", "plot_molecule"),
60+
"infer_bonds": ("common.molecule_viz", "infer_bonds"),
61+
"infer_angles_from_bonds": ("common.molecule_viz", "infer_angles_from_bonds"),
62+
}
63+
64+
__all__ = [
65+
"__version__",
66+
*_EXPORTS.keys(),
9667
]
68+
69+
70+
def __getattr__(name: str) -> Any:
71+
return load_export(
72+
package_name=__name__,
73+
package_globals=globals(),
74+
exports=_EXPORTS,
75+
name=name,
76+
)
77+
78+
79+
def __dir__() -> list[str]:
80+
import sys
81+
82+
return list_exports(sys.modules[__name__], _EXPORTS)

common/lazy.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from __future__ import annotations
2+
3+
from importlib import import_module
4+
from types import ModuleType
5+
from typing import Any
6+
7+
LazyExports = dict[str, tuple[str, str]]
8+
9+
10+
def load_export(
11+
*,
12+
package_name: str,
13+
package_globals: dict[str, Any],
14+
exports: LazyExports,
15+
name: str,
16+
) -> Any:
17+
"""Resolve and memoize a lazily exported package attribute."""
18+
try:
19+
module_name, attr_name = exports[name]
20+
except KeyError as exc:
21+
raise AttributeError(
22+
f"module {package_name!r} has no attribute {name!r}"
23+
) from exc
24+
25+
value = getattr(import_module(module_name), attr_name)
26+
package_globals[name] = value
27+
return value
28+
29+
30+
def list_exports(module: ModuleType, exports: LazyExports) -> list[str]:
31+
"""Return names exposed by a package module plus its lazy exports."""
32+
return sorted(set(vars(module)) | set(exports))

0 commit comments

Comments
 (0)