Repository: matchms/matchms

Issue:
Add progress bars to score computation
Currently the matrix function in BaseSimilarity does not show any progress bars. For larger datasets that can take minutes -> hours to process this is impractical. 

Solution: Implement process bar tracking progress.

Discussion:

Solution patch:
diff --git a/README.rst b/README.rst
index 2d73931a..458710fb 100644
--- a/README.rst
+++ b/README.rst
@@ -323,7 +323,7 @@ To install matchms, do:
   # Install rdkit using conda, rest of dependencies can be installed with pip
   conda install -c conda-forge rdkit
   python -m pip install --upgrade pip
-  pip install --editable .[dev]  # if this won't work try "poetry install --with dev"
+  pip install --editable .[dev]  # if this won't work try `pip install --editable ".[dev]"`, alternatively you can `poetry install --with dev``
 
 Run the linter with:
 
diff --git a/matchms/exporting/save_as_mgf.py b/matchms/exporting/save_as_mgf.py
index 1d8fa37a..6dd415c4 100644
--- a/matchms/exporting/save_as_mgf.py
+++ b/matchms/exporting/save_as_mgf.py
@@ -10,11 +10,11 @@ logger = logging.getLogger("matchms")
 
 
 @rename_deprecated_params(param_mapping={"spectrums": "spectra"}, version="0.26.5")
-def save_as_mgf(
-    spectra: Union[List[Spectrum], Spectrum],
-    filename: str,
-    export_style: str = "matchms",
-):
+def save_as_mgf(spectra: Union[List[Spectrum], Spectrum],
+                filename: str,
+                export_style: str = "matchms",
+                file_mode: str = "a",
+                ) -> None:
     """Save spectrum(s) as mgf file.
 
     Example:
@@ -44,6 +44,9 @@ def save_as_mgf(
     export_style:
         Converts the keys to the required export style. One of ["matchms", "massbank", "nist", "riken", "gnps"].
         Default is "matchms"
+    file_mode: str
+        This is an optional parameter which defines the mode the file will be opened in.  
+        Default is "a" (append). The other option is "w" (write). If set worngly it will default to "a".
     """
     if not isinstance(spectra, list):
         # Assume that input was a single Spectrum.
@@ -63,7 +66,6 @@ def save_as_mgf(
             if "fingerprint" in spectrum_dict["params"]:
                 del spectrum_dict["params"]["fingerprint"]
             yield spectrum_dict
-
-    py_mgf.write(
-        spectrum_dict_generator(spectra), filename, file_mode="a", encoding="utf-8"
-    )
+    if file_mode not in ["a", "w"]:
+        file_mode = "a"
+    py_mgf.write(spectrum_dict_generator(spectra), filename, file_mode=file_mode, encoding="utf-8")
\ No newline at end of file
diff --git a/matchms/similarity/BaseSimilarity.py b/matchms/similarity/BaseSimilarity.py
index 0ab33c46..1dbb9ccb 100644
--- a/matchms/similarity/BaseSimilarity.py
+++ b/matchms/similarity/BaseSimilarity.py
@@ -2,6 +2,7 @@ from abc import abstractmethod
 from typing import List
 import numpy as np
 from sparsestack import StackedSparseArray
+from tqdm import tqdm
 from matchms.typing import SpectrumType
 
 
@@ -64,12 +65,13 @@ class BaseSimilarity:
         n_cols = len(queries)
 
         if is_symmetric and n_rows != n_cols:
-            raise ValueError(f"Found unequal number of spectra {n_rows} and {n_cols} in while `is_symmetric` is True.")
+            raise ValueError(f"Found unequal number of spectra {n_rows} and {n_cols} while `is_symmetric` is True.")
 
         idx_row = []
         idx_col = []
         scores = []
-        for i_ref, reference in enumerate(references[:n_rows]):
+        # Wrap the outer loop with tqdm to track progress
+        for i_ref, reference in enumerate(tqdm(references[:n_rows], desc="Calculating similarities")):
             if is_symmetric and self.is_commutative:
                 for i_query, query in enumerate(queries[i_ref:n_cols], start=i_ref):
                     score = self.pair(reference, query)
@@ -128,7 +130,8 @@ class BaseSimilarity:
 
         assert idx_row.shape == idx_col.shape, "col and row indices must be of same shape"
         scores = np.zeros((len(idx_row)), dtype=self.score_datatype)  # TODO: switch to sparse matrix
-        for i, row in enumerate(idx_row):
+        # Use tqdm to track progress through the indices
+        for i, row in enumerate(tqdm(idx_row, desc="Calculating sparse similarities")):
             col = idx_col[i]
             scores[i] = self.pair(references[row], queries[col])
         return scores


Test patch:
diff --git a/tests/exporting/test_save_as_mgf.py b/tests/exporting/test_save_as_mgf.py
index 7c3c4ee1..ad0433a2 100644
--- a/tests/exporting/test_save_as_mgf.py
+++ b/tests/exporting/test_save_as_mgf.py
@@ -28,10 +28,13 @@ def test_save_as_mgf_single_spectrum():
     # Write to test file
     with tempfile.TemporaryDirectory() as d:
         filename = os.path.join(d, "test.mgf")
+        filename2 = os.path.join(d, "test2.mgf")
         save_as_mgf(spectrum, filename)
+        save_as_mgf(spectrum, filename2, file_mode="w")
 
         # test if file exists
         assert os.path.isfile(filename)
+        assert os.path.isfile(filename2)
 
         # Test if content of mgf file is correct
         with open(filename, "r", encoding="utf-8") as f: