Repository: matchms/matchms

Issue:
Add more possible field names to add precursor mz values from metadata
**Problem**
The code below currently only allows precursor m/z related data in `pepmass` or `precursor_mz` while fields such as `percursormz` etc. are ignored.

**Solution**
Expand the dictionary of allowed keys that can be used to store the precursor m/z values in the file's metadata.

https://github.com/matchms/matchms/blob/04af51cec2eedf6ca2c398b44b614e387e309f16/matchms/filtering/add_precursor_mz.py#L4-L24

Comments:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69fc630d..76c8e954 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Changed
 
+- `add_precursor_mz()` filter now also checks for metadata in keys `precursormz` and `precursor_mass` [#223](https://github.com/matchms/matchms/pull/223)
 - `load_from_msp()` now handles .msp files containing multiple peaks per line separated by `;` [#221](https://github.com/matchms/matchms/pull/221)
 
 ## [0.8.2] - 2021-03-08
diff --git a/matchms/filtering/add_precursor_mz.py b/matchms/filtering/add_precursor_mz.py
index 9e402764..2022653f 100644
--- a/matchms/filtering/add_precursor_mz.py
+++ b/matchms/filtering/add_precursor_mz.py
@@ -1,6 +1,21 @@
+from typing import Iterable
+from typing import TypeVar
 from ..typing import SpectrumType
 
 
+_T = TypeVar('_T')
+_accepted_keys = ["precursor_mz", "precursormz", "precursor_mass"]
+_accepted_types = (float, str, int)
+_convertible_types = (str, int)
+
+
+def get_first_common_element(first: Iterable[_T], second: Iterable[_T]) -> _T:
+    """ Get first common element from two lists.
+    Returns 'None' if there are no common elements.
+    """
+    return next((item for item in first if item in second), None)
+
+
 def add_precursor_mz(spectrum_in: SpectrumType) -> SpectrumType:
     """Add precursor_mz to correct field and make it a float.
 
@@ -12,10 +27,19 @@ def add_precursor_mz(spectrum_in: SpectrumType) -> SpectrumType:
 
     spectrum = spectrum_in.clone()
 
-    if isinstance(spectrum.get("precursor_mz", None), str):
-        spectrum.set("precursor_mz", float(spectrum.get("precursor_mz").strip()))
-    elif spectrum.get("precursor_mz", None) is None:
-        pepmass = spectrum.get("pepmass", None)
+    precursor_mz_key = get_first_common_element(spectrum.metadata.keys(), _accepted_keys)
+    precursor_mz = spectrum.get(precursor_mz_key)
+
+    if isinstance(precursor_mz, _accepted_types):
+        if isinstance(precursor_mz, str):
+            try:
+                precursor_mz = float(precursor_mz.strip())
+            except ValueError:
+                print("%s can't be converted to float.", precursor_mz)
+                return spectrum
+        spectrum.set("precursor_mz", float(precursor_mz))
+    elif precursor_mz is None:
+        pepmass = spectrum.get("pepmass")
         if pepmass is not None and isinstance(pepmass[0], float):
             spectrum.set("precursor_mz", pepmass[0])
         else:


Test patch:
diff --git a/tests/test_add_precursor_mz.py b/tests/test_add_precursor_mz.py
index 920bd282..e644159b 100644
--- a/tests/test_add_precursor_mz.py
+++ b/tests/test_add_precursor_mz.py
@@ -1,4 +1,5 @@
 import numpy
+import pytest
 from matchms import Spectrum
 from matchms.filtering import add_precursor_mz
 
@@ -45,18 +46,28 @@ def test_add_precursor_mz_only_pepmass_present():
     assert spectrum.get("precursor_mz") == 444.0, "Expected different precursor_mz."
 
 
-def test_add_precursor_mz_no_precursor_mz():
+@pytest.mark.parametrize("key, value, expected", [
+    ["precursor_mz", "444.0", 444.0],
+    ["precursormz", "15.6", 15.6],
+    ["precursormz", 15.0, 15.0],
+    ["precursor_mass", "17.887654", 17.887654],
+    ["precursor_mass", "N/A", None],
+    ["precursor_mass", "test", None],
+    ["pepmass", (33.89, 50), 33.89],
+    ["pepmass", "None", None],
+    ["pepmass", None, None]])
+def test_add_precursor_mz_no_precursor_mz(key, value, expected):
     """Test if precursor_mz is correctly derived if "precursor_mz" is str."""
     mz = numpy.array([], dtype='float')
     intensities = numpy.array([], dtype='float')
-    metadata = {"precursor_mz": "444.0"}
+    metadata = {key: value}
     spectrum_in = Spectrum(mz=mz,
                            intensities=intensities,
                            metadata=metadata)
 
     spectrum = add_precursor_mz(spectrum_in)
 
-    assert spectrum.get("precursor_mz") == 444.0, "Expected different precursor_mz."
+    assert spectrum.get("precursor_mz") == expected, "Expected different precursor_mz."
 
 
 def test_empty_spectrum():