Add NMR data model, integration with EnzymeML, and peak assignment features#13
Add NMR data model, integration with EnzymeML, and peak assignment features#13torogi94 wants to merge 69 commits into
Conversation
|
@torogi94 Thanks for this!
|
|
Thank you for looking over it! Here, a few comments:
Good catch! I really did forget to declare the new dependencies in the requirements.txt file. I think you are right that we should not necessarily introduce them to the core of NMRpy. How about we declare them as optional nmrpy[enzymeml]? For the NMRpy data model, however, it would be easier if we could make pydantic a core dependency. If I am not mistaken, it is the only one required for the data model to work. If not, I can restructure my code, so the data model part becomes entirely optional, too, though.
We are preparing a new stable pyenzyme (v2) release which we can then pin in the requirements. In my experience, it is already running better and will be more maintainable than the previous v1 version. With regard to md-models, the NMRpy data model is not dependent at all on the md-models version. Actually, it is not even a dependency needed, as all functionalities are handled via pydantic, which is itself a very well maintained library!
Absolutely. I’ll merge main into my branch and fix the conflict manually so you can have a clean merge without conflicts!
Sorry for the noisy diff, it seems I accidentally let my linter loose on the two files and did not even notice... I’ll revert the linting changes from this PR and submit them in a separate PR (like discussed). |
I agree with making pydantic a core dependency and the others as optional in On another note. I also have a conda build recipe as well as a CI job that builds and distributes a conda package. This has been very easy to date because NMRPy is a pure python package and there are/were conda packages available for all of the dependencies (channel conda-forge). Is PyEnzyme released as a conda package? I would like to continue distributing conda packages, just as we do for PySCeS as well.
Okay great.
Give me a ping once you are ready with all of this then I'll proceed with the detailed code review 😄 |
|
I think I have addressed all points mentioned so far, so you may continue with the detailed code review now!
I am in contact with @JR-1991 about the |
|
I have addressed a few more issues we discussed in pull requests #14 and #15 and merged them with this pull request:
|
|
@jmrohwer: In #18, I have added handling of t0 values in |
8182bfc to
9f55722
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces an NMR-focused research data model aligned with md-models/EnzymeML, adds EnzymeML integration (via optional pyenzyme), and extends interactive widgets for peak assignment and measurement editing.
Changes:
- Added NMRpy/EnzymeML-aligned data model specifications and an auto-generated Pydantic schema (JSON-LD capable).
- Implemented EnzymeML helpers (species lookup, measurement construction, applying concentrations) and new peak/t0/measurement widgets.
- Updated packaging/tooling (optional extras for EnzymeML, dependency bumps, Ruff config) and added/extended tests.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| specifications/nmrpy.md | Adds written spec for the NMRpy data model objects/enums. |
| specifications/datamodel_schema.md | Adds Mermaid class diagram for the data model structure. |
| setup.py | Adds EnzymeML optional extras and updates author metadata. |
| ruff.toml | Introduces Ruff formatting/lint configuration. |
| requirements.txt | Updates baseline dependencies and adds pydantic. |
| nmrpy/utils.py | Adds EnzymeML utility helpers (species, measurements, serialization helpers). |
| nmrpy/tests/nmrpy_tests.py | Adds tests for new data model + EnzymeML-related setters. |
| nmrpy/plotting.py | Adds peak assignment + t0/measurement widgets and integrates EnzymeML utilities. |
| nmrpy/nmrpy_model.py | Adds generated Pydantic models for the NMRpy data model (JSON-LD fields). |
| nmrpy/data_objects.py | Integrates data model + EnzymeML into Fid/FidArray and processing steps tracking. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from typing import Mapping, Optional | ||
|
|
||
| from pyenzyme.versions.v2 import Protein |
There was a problem hiding this comment.
This unconditional pyenzyme import will raise at import-time when pyenzyme isn't installed, even though the rest of the file treats it as an optional dependency. Move Protein into the existing try: block (or avoid importing it directly and use getattr(pyenzyme, ...) / isinstance(..., pyenzyme.Protein) inside the guarded section).
There was a problem hiding this comment.
@torogi94 Please look into this and confirm that you agree. Only usage of Protein is in line 1758. How will this affect the functionality if pyenzyme is not installed? Does the PeakAssigner class depend on pyenzyme? I'm assuming so, see
Lines 1467 to 1475 in 1928d7c
Thus seems okay to move the Protein import into the existing try/except block. Done.
| self.__fid_object.raw_data = [str(datum) for datum in self.raw_data] | ||
| self.__fid_object.processed_data = [float(datum) for datum in self.data] | ||
| except AttributeError: |
There was a problem hiding this comment.
float(datum) will raise TypeError when self.data contains complex values (common before .real()), but only AttributeError is caught here. Update serialization logic to handle complex processed data (e.g., store strings for complex values) and/or catch TypeError to avoid hard crashes when accessing fid_object.
| self.__fid_object.raw_data = [str(datum) for datum in self.raw_data] | |
| self.__fid_object.processed_data = [float(datum) for datum in self.data] | |
| except AttributeError: | |
| # Always serialise raw_data as strings | |
| self.__fid_object.raw_data = [str(datum) for datum in self.raw_data] | |
| # Serialise processed_data, handling complex or otherwise non-floatable values gracefully | |
| processed_data = [] | |
| for datum in self.data: | |
| try: | |
| processed_data.append(float(datum)) | |
| except (TypeError, ValueError): | |
| # Fallback for complex or non-scalar values: store string representation | |
| processed_data.append(str(datum)) | |
| self.__fid_object.processed_data = processed_data | |
| except (AttributeError, TypeError): |
There was a problem hiding this comment.
Calling float(datum) on a complex128 will not raise a TypeError but just issue a ComplexWarning and discard the imaginary part. Are we going to just ignore this error message? The point is, do you want the FIDObject to handle complex data in the processed_data list? This is an object that got introduced with the data model.
- Added T0Tab and T0Logic classes to utils.py - Added T0Adder widget class to plotting.py - Added add_t0_to_enzymeml() method that can be used interactively with a Jupyter widget using gui=True or script-like with gui=False
Changed behaviour of Fid._setup_peak_objects(). Multiple peaks per range are handled properly now by using Fid._grouped_peaklist instead of Fid.peaks. Also refactored the method to make it more robust and readable overall.
- Added NMR parameters to fid_object setter - Fixed p0 and p1 phasing parameter assignment
ccb2087 to
27ef6e3
Compare
- Added tests for all of utils.py - Added tests for new widgets in plotting.py - Removed unused imports from nmrpy_tests.py
- Added information on optional installs to installation.rst - Added data model information to intro.rst - Added utils.py information to new utility_objects.rst - Updated index.rst - Described new features in quickstart.rst - Added screenshots to _static/
|
@torogi94 Before merge, we actually need to deal with the Copilot comments. I've been through the code and they have not yet been applied. Most of them seem useful and true, and indeed correct errors, so I'd appreciate it if you could go through them yourself as well. The issue of |
|
@torogi94 I have dealt with most of the remaining issues from the Copilot review, but there are some outstanding ones that you need to deal with - I have mentioned you in the comments. Please review the changes in the last commit (79f1ff5) if you agree. Also FYI I updated the build system to use |
|
3 more commits to fix compatibility bugs. Numpy 2.5 has many deprecations, so the Furthermore another numpy 2.4 (which numpy are you using @torogi94 ?) deprecation caused one of the tests to fail. Fixed. Also fixed another bug that manifested if pyenzyme was not installed. Checked that all tests (except plotting) now pass when pyenzyme is installed and when not. In a new environment with the latest version of all packages. |
|
Updated the scripts for Anaconda build and for CI. The tests are split out now that first the tests run without |
md-models-based research data model for NMRpyenzymelibrary