Renamed pacakge from qcio to qcdata - #99
Conversation
37531a0 to
623f861
Compare
… as the dominant name over Results.
623f861 to
e12a400
Compare
There was a problem hiding this comment.
Pull request overview
This PR renames the Python package from qcio to qcdata, updates imports/references across the codebase, and introduces/updates compatibility layers so existing downstream users can transition with minimal breakage.
Changes:
- Renames project/package metadata and updates dependencies, tooling, and CI to use
qcdata. - Refactors output container models to make
ProgramOutputprimary again and demoteResultsto a deprecated alias (with compatibility shims). - Updates tests, docs, and serialized artifacts (e.g., XYZ comment prefixes) to the new
qcdatanaming.
Reviewed changes
Copilot reviewed 60 out of 65 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| uv.lock | Updates locked dependency names to qcdata. |
| pyproject.toml | Renames the distribution to qcdata and updates project URLs/tooling config. |
| scripts/tests.sh | Updates coverage target from qcio to qcdata. |
| .github/workflows/test.yaml | Updates CI coverage target to qcdata. |
| .github/workflows/publish-to-pypi.yaml | Updates PyPI project URL to qcdata. |
| src/qcdata/init.py | Adds qcdata package entrypoint and exports/public API. |
| src/qcio/init.py | Replaces old qcio entrypoint with a deprecated compatibility shim. |
| src/qcdata/helper_types.py | Introduces shared annotated helper types (e.g., SerializableNDArray). |
| src/qcdata/utils.py | Updates module docstring to qcdata naming. |
| src/qcdata/view.py | Updates viewer code to use qcdata types and terminology. |
| src/qcdata/qcel.py | Updates QCElemental interop imports and naming (qcio → qcdata). |
| src/qcdata/py.typed | Marks the package as typed for type checkers. |
| src/qcdata/models/init.py | Re-exports models, switching from results to outputs module. |
| src/qcdata/models/base_models.py | Renames base model class to QCDataBaseModel and updates docstrings. |
| src/qcdata/models/data.py | Splits/clarifies “structured data” models and updates naming. |
| src/qcdata/models/outputs.py | Adds ProgramOutput as primary output container and Results deprecated alias. |
| src/qcdata/models/results.py | Adds compatibility module for legacy qcdata.models.results imports. |
| src/qcdata/models/inputs.py | Updates docstring examples to qcdata.models import paths. |
| src/qcdata/models/structure.py | Updates base class/imports and changes XYZ comment prefixes to qcdata_*. |
| src/qcdata/models/utils.py | Updates TYPE_CHECKING import to qcdata. |
| tests/conftest.py | Renames fixtures and imports to use ProgramOutput/qcdata. |
| tests/test_package_api.py | Updates wildcard import test to qcdata. |
| tests/test_calc_input.py | Updates imports from qcio to qcdata. |
| tests/test_file_input.py | Updates imports from qcio to qcdata. |
| tests/test_files.py | Updates imports from qcio.models to qcdata.models. |
| tests/test_conformer_search_data.py | Updates imports from qcio to qcdata. |
| tests/test_qcel.py | Updates qcel helper imports to qcdata.qcel. |
| tests/test_view.py | Updates imports and output type (Results → ProgramOutput). |
| tests/test_serialization.py | Updates serialization tests to ProgramOutput. |
| tests/test_structure.py | Updates imports and expected XYZ prefix strings to qcdata_*. |
| tests/test_optimization_data.py | Updates tests to use ProgramOutput terminology and qcdata_* prefixes. |
| tests/test_outputs.py | Adds dedicated tests for output-container behaviors under ProgramOutput. |
| tests/test_single_point_data.py | Adds focused tests for SinglePointData/Wavefunction numpy coercions and validators. |
| tests/test_results.py | Removes old combined results/output tests (superseded by new split tests). |
| tests/data/structures.py | Updates fixture imports to qcdata. |
| tests/data/caffeine.xyz | Updates XYZ comment prefixes from qcio_* to qcdata_*. |
| tests/data/multi.xyz | Updates XYZ comment prefixes from qcio_* to qcdata_*. |
| mkdocs.yml | Renames site/project references and restructures API nav (outputs/data/results alias). |
| docs/CNAME | Updates docs domain from qcio.* to qcdata.*. |
| docs/index.md | Updates docs landing page branding, badges, links, and install snippets to qcdata. |
| docs/why.md | Updates “Why” page references from qcio to qcdata. |
| docs/dev-docs/dev-decisions.md | Updates design decision doc references from Results to ProgramOutput. |
| docs/visualizations/overview.md | Updates install snippets and terminology to qcdata/ProgramOutput. |
| docs/visualizations/structure.ipynb | Updates notebook imports and embedded XYZ prefixes to qcdata_*. |
| docs/visualizations/U1-_mmff94s_180-opt-terachem-thf.json | Updates embedded filenames/strings from qcio_* to qcdata_*. |
| docs/api/overview.md | Updates API mental model section to qcdata and new outputs/data separation. |
| docs/api/inputs.md | Updates API docs to reference qcdata and ProgramOutput. |
| docs/api/outputs.md | Adds a new Outputs API page for ProgramOutput + deprecated Results alias. |
| docs/api/data.md | Adds a new Data API page for structured output payload models. |
| docs/api/results.md | Refactors Results API page to document it as deprecated alias. |
| docs/api/structure.md | Updates directive targets to qcdata.*. |
| docs/api/files.md | Updates directive target to qcdata.Files. |
| docs/api/model.md | Updates directive target to qcdata.Model. |
| docs/api/provenance.md | Updates directive target to qcdata.Provenance. |
| docs/api/lengthunit.md | Updates directive target to qcdata.LengthUnit. |
| docs/api/calctype.md | Updates directive target to qcdata.CalcType. |
| docs/api/view.md | Updates directive target to qcdata.view. |
| docs/api/utils.md | Updates directive targets to qcdata.json_dumps / qcdata.to_multi_xyz. |
| docs/api/qciobasemodel.md | Removes old QCIO base-model API doc page. |
| docs/api/qcdatabasemodel.md | Adds new QCData base-model API doc page. |
| README.md | Updates README branding/links to qcdata, and revises narrative toward ProgramOutput/Data. |
| CHANGELOG.md | Adds changelog notes about the rename and model/test/doc reorganization. |
| .vscode/settings.json | Updates VS Code spelling dictionary entry (QCIO → QCDATA). |
Comments suppressed due to low confidence (4)
tests/test_structure.py:200
- This parametrized test block is named like it covers backwards-compatibility parsing of XYZ comment keys, but the cases were updated from
qcio_charge/qcio_multiplicitytoqcdata_*. If you intend to keep compatibility with existingqcio_*-prefixed XYZ files, it would be good to keep/add explicitqcio_*cases here (in addition to the newqcdata_*ones).
src/qcdata/models/data.py:160 - The validation error message still says "SinglePointResults requires ..." but the class is
SinglePointData. Updating the message would avoid confusion for users seeing this ValidationError.
README.md:45 - The README quickstart uses
CalcInputandCompositeCalcInput, but those symbols don’t appear to exist in the currentqcdatapackage (the codebase usesProgramInput/DualProgramInput). As-is, the documented examples will fail for users. Either update the docs to the supported API, or add/restore aliases with deprecation guidance.
#### CalcInput - Core input object for a single QC calculation.
```python
from qcdata import Structure, CalcInput
# xyz files or saved Structure objects can be opened from disk
caffeine = Structure.open("caffeine.xyz")
# Define the program input
prog_input = CalcInput(
structure=caffeine,
src/qcdata/models/structure.py:336
Structure.from_xyznow only recognizesqcdata_/qcdata__identifiers_prefixes. This breaks loading older XYZ files written with the previousqcio_prefixes. If backwards compatibility is a goal (there’s aqcioshim elsewhere), consider accepting bothqcio_*andqcdata_*prefixes when parsing comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| options: | ||
| members: false |
There was a problem hiding this comment.
The mkdocstrings options block is not indented under the ::: qcdata.Results directive, so it likely won’t be applied (and will render as plain text). Please indent options:/members: to match the convention used elsewhere in docs/api/*.
| options: | |
| members: false | |
| options: | |
| members: false |
| options: | ||
| members: false | ||
|
|
||
| ::: qcdata.OptimizationData | ||
| options: | ||
| members: | ||
| - structures | ||
| - final_structure | ||
| - energies | ||
| - final_energy | ||
| - to_xyz | ||
| - save |
There was a problem hiding this comment.
The mkdocstrings option blocks in this file (e.g., for SinglePointData / OptimizationData) are not indented under their ::: directives, which likely prevents mkdocstrings from applying them. Please indent options: and its fields to match other API doc pages.
| options: | |
| members: false | |
| ::: qcdata.OptimizationData | |
| options: | |
| members: | |
| - structures | |
| - final_structure | |
| - energies | |
| - final_energy | |
| - to_xyz | |
| - save | |
| options: | |
| members: false | |
| ::: qcdata.OptimizationData | |
| options: | |
| members: | |
| - structures | |
| - final_structure | |
| - energies | |
| - final_energy | |
| - to_xyz | |
| - save |
| @model_validator(mode="after") | ||
| def ensure_traceback_on_failure(self) -> Self: | ||
| if self.success is False: | ||
| assert self.traceback is not None, ( | ||
| "A traceback must be provided for failed calculations." | ||
| ) | ||
| return self | ||
|
|
||
| @model_validator(mode="after") | ||
| def _ensure_structured_results_on_success(self) -> Self: | ||
| """Ensure structured results are provided for successful, non FileInputs.""" | ||
| if self.success is True and isinstance(self.input_data, ProgramInput): | ||
| assert type(self.data) is not Files, ( | ||
| "Structured results must be provided for successful, non FileInput " | ||
| "calculations." | ||
| ) | ||
| return self | ||
|
|
||
| @model_validator(mode="after") | ||
| def ensure_primary_result_on_success(self) -> Self: | ||
| if type(self.data) is SinglePointData: | ||
| calctype_val = self.input_data.calctype.value # type: ignore | ||
| assert getattr(self.data, calctype_val) is not None, ( | ||
| f"Missing the primary result: {calctype_val}." | ||
| ) | ||
| return self |
There was a problem hiding this comment.
These validators use assert for runtime validation. assert statements are stripped when Python is run with optimizations (-O), which would silently disable critical validation (e.g., missing traceback on failures). Prefer raising ValueError/TypeError instead of assert in validators.
| caffeine = Structure.open(test_data_dir / "caffeine.xyz") | ||
| caffeine.save(tmp_path / "caffeine_copy.xyz") | ||
| caffeine_copy = Structure.open(tmp_path / "caffeine_copy.xyz") | ||
| assert caffeine_copy.symbols == caffeine.symbols | ||
| assert np.allclose(caffeine.geometry, qcio_structures.caffeine.geometry, rtol=1e-9) | ||
| assert np.allclose(caffeine.geometry, qcdata_structures.caffeine.geometry, rtol=1e-9) | ||
| assert caffeine_copy.multiplicity == caffeine.multiplicity | ||
| assert caffeine_copy.charge == caffeine.charge |
There was a problem hiding this comment.
In test_to_file_xyz, the geometry assertion compares caffeine.geometry against the fixture geometry, but it never verifies caffeine_copy.geometry. This means the test won’t catch geometry serialization/deserialization regressions in the saved copy. Consider asserting against caffeine_copy.geometry here.
| options: | ||
| members: false | ||
|
|
||
| ## Deprecated Alias | ||
|
|
||
| ::: qcdata.Results | ||
| options: | ||
| members: false |
There was a problem hiding this comment.
The mkdocstrings directive options here aren’t indented under the ::: qcdata.ProgramOutput directive (unlike other API docs pages in this repo). As written, options:/members: will likely render as plain text and not configure mkdocstrings. Please indent these lines to match the pattern used in e.g. docs/api/structure.md.
| options: | |
| members: false | |
| ## Deprecated Alias | |
| ::: qcdata.Results | |
| options: | |
| members: false | |
| options: | |
| members: false | |
| ## Deprecated Alias | |
| ::: qcdata.Results | |
| options: | |
| members: false |
| @@ -1,16 +1,16 @@ | |||
| Being able to quickly and easily visualize results is critical for efficient scientific work. `qcio` come with build-in visualizations for all objects. | |||
| Being able to quickly and easily visualize results is critical for efficient scientific work. `qcdata` come with build-in visualizations for all objects. | |||
There was a problem hiding this comment.
Grammar: "qcdata come with build-in visualizations" should be "qcdata comes with built-in visualizations".
| Being able to quickly and easily visualize results is critical for efficient scientific work. `qcdata` come with build-in visualizations for all objects. | |
| Being able to quickly and easily visualize results is critical for efficient scientific work. `qcdata` comes with built-in visualizations for all objects. |
| # Why qcdata? | ||
|
|
||
| Other data structure package for quantum chemistry exist such as [QCElemental](https://github.com/MolSSI/QCElemental) and [Atomic Simulation Environment](https://wiki.fysik.dtu.dk/ase/index.html). I often found these libraries were too heavy weight or too feature poor for most of what I needed. I also found their APIs to be somewhat unintuitive and often cumbersome to use. `qcio` is designed to be easy to use, easy to reason about, and provide a unified format for diverse quantum chemistry calculations. | ||
| Other data structure package for quantum chemistry exist such as [QCElemental](https://github.com/MolSSI/QCElemental) and [Atomic Simulation Environment](https://wiki.fysik.dtu.dk/ase/index.html). I often found these libraries were too heavy weight or too feature poor for most of what I needed. I also found their APIs to be somewhat unintuitive and often cumbersome to use. `qcdata` is designed to be easy to use, easy to reason about, and provide a unified format for diverse quantum chemistry calculations. |
There was a problem hiding this comment.
Grammar: "Other data structure package ... exist" should be plural, and "heavy weight"/"feature poor" are typically written "heavyweight"/"feature-poor".
| Other data structure package for quantum chemistry exist such as [QCElemental](https://github.com/MolSSI/QCElemental) and [Atomic Simulation Environment](https://wiki.fysik.dtu.dk/ase/index.html). I often found these libraries were too heavy weight or too feature poor for most of what I needed. I also found their APIs to be somewhat unintuitive and often cumbersome to use. `qcdata` is designed to be easy to use, easy to reason about, and provide a unified format for diverse quantum chemistry calculations. | |
| Other data structure packages for quantum chemistry exist such as [QCElemental](https://github.com/MolSSI/QCElemental) and [Atomic Simulation Environment](https://wiki.fysik.dtu.dk/ase/index.html). I often found these libraries were too heavyweight or too feature-poor for most of what I needed. I also found their APIs to be somewhat unintuitive and often cumbersome to use. `qcdata` is designed to be easy to use, easy to reason about, and provide a unified format for diverse quantum chemistry calculations. |
| if "stdout" in payload: | ||
| warnings.warn( | ||
| "The 'stdout' attribute has been renamed to 'logs'. Please update your " | ||
| "code accordingly.", | ||
| category=FutureWarning, | ||
| stacklevel=2, | ||
| ) | ||
| if "logs" not in payload: | ||
| payload["logs"] = payload.pop("stdout") | ||
|
|
||
| if "results" in payload: | ||
| warnings.warn( | ||
| "The 'results' attribute has been renamed to 'data'. Please update " | ||
| "your code accordingly.", | ||
| category=FutureWarning, | ||
| stacklevel=2, | ||
| ) | ||
| if isinstance(payload["results"], dict): | ||
| payload["data"] = payload.pop("results") | ||
|
|
There was a problem hiding this comment.
In the backwards-compatibility pre-validator, legacy keys like stdout and results are only removed in some cases. If a payload contains both stdout+logs (or non-dict results), the legacy key will remain and then fail validation because QCDataBaseModel forbids extra fields. Consider always pop()-ing stdout/results when present (and mapping them onto logs/data only when the new field is absent).
| if "files" in payload: | ||
| warnings.warn( | ||
| "The 'files' attribute has been moved to 'data.files'. Please " | ||
| "update your code accordingly.", | ||
| category=FutureWarning, | ||
| stacklevel=2, | ||
| ) | ||
| if isinstance(payload["data"], dict): | ||
| data_files_dict = payload["data"].get("files", {}) | ||
| else: | ||
| data_files_dict = payload["data"].files | ||
|
|
||
| data_files_dict.update(**payload.pop("files")) | ||
|
|
There was a problem hiding this comment.
_backwards_compatibility assumes payload["data"] exists when files is present. If an old payload includes top-level files without data/results (or results was non-dict and not migrated), this will raise KeyError inside the validator and mask the real validation problem. Suggest guarding for missing data and/or migrating results→data for all types before trying to merge files.
| def __repr_args__(self) -> list[tuple[str, Any]]: | ||
| """Exclude stdout and traceback from the repr and ensure success is first.""" | ||
| args = super().__repr_args__() | ||
| filtered_args = [ | ||
| (key, value if key not in {"stdout", "traceback"} else "<...>") | ||
| for key, value in args | ||
| ] | ||
| success_arg = [(key, value) for key, value in filtered_args if key == "success"] | ||
| other_args = [(key, value) for key, value in filtered_args if key != "success"] | ||
| return success_arg + other_args |
There was a problem hiding this comment.
__repr_args__ masks keys {"stdout", "traceback"}, but this model’s field is logs (and stdout is only a compatibility property). As written, large logs strings will still be included in the repr. Consider filtering/masking logs (and traceback) instead.
No description provided.