Repository: matchms/matchms
Pull request #499 (2023-08-21 14:26:56)

Improve default pipelines
Sorry for this large PR, some of the rebasing went a bit wrong, so I combined two PR in one. Hope it is still clear.

The default pipelines for library cleaning are not yet complete and tests for the filter order are limited.

- [x] Add tests for known orders in order filter
- [x] Add tests missing from the predefined_pipelines
- [x] Move ALL_FILTERS to filter_order_and_default_pipelines
- [x] Moved metadata_utils to filter utils

In addition #500 ProgressReport can count one spectrum multiple times is fixed. 


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=matchms_matchms&pullRequest=499)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=matchms_matchms&pullRequest=499&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=matchms_matchms&pullRequest=499&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=matchms_matchms&pullRequest=499&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=matchms_matchms&pullRequest=499&resolved=false&types=CODE_SMELL)

[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=matchms_matchms&pullRequest=499&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=matchms_matchms&pullRequest=499&metric=new_coverage&view=list)  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=matchms_matchms&pullRequest=499&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=matchms_matchms&pullRequest=499&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/matchms/Pipeline.py b/matchms/Pipeline.py
index 32214b4e..e8e941b0 100644
--- a/matchms/Pipeline.py
+++ b/matchms/Pipeline.py
@@ -5,11 +5,11 @@ from typing import Iterable, List, Optional, Union
 import yaml
 import matchms.similarity as mssimilarity
 from matchms import calculate_scores
+from matchms.filtering.SpectrumProcessor import SpectrumProcessor
 from matchms.importing.load_spectra import load_list_of_spectrum_files
 from matchms.logging_functions import (add_logging_to_file,
                                        reset_matchms_logger,
                                        set_matchms_logger_level)
-from matchms.SpectrumProcessor import SpectrumProcessor
 from matchms.typing import SpectrumType
 
 
diff --git a/matchms/__init__.py b/matchms/__init__.py
index 515e05f6..2533280b 100644
--- a/matchms/__init__.py
+++ b/matchms/__init__.py
@@ -1,3 +1,4 @@
+from matchms.filtering.SpectrumProcessor import SpectrumProcessor
 from . import exporting, filtering, importing, networking, plotting, similarity
 from .__version__ import __version__
 from .calculate_scores import calculate_scores
@@ -8,7 +9,6 @@ from .Metadata import Metadata
 from .Pipeline import Pipeline
 from .Scores import Scores
 from .Spectrum import Spectrum
-from .SpectrumProcessor import SpectrumProcessor
 
 
 _init_logger()
diff --git a/matchms/SpectrumProcessor.py b/matchms/filtering/SpectrumProcessor.py
similarity index 70%
rename from matchms/SpectrumProcessor.py
rename to matchms/filtering/SpectrumProcessor.py
index 088513cc..f8ce9280 100644
--- a/matchms/SpectrumProcessor.py
+++ b/matchms/filtering/SpectrumProcessor.py
@@ -4,8 +4,9 @@ from typing import Dict, Optional, Tuple, Union
 import numpy as np
 import pandas as pd
 from tqdm import tqdm
-import matchms.filtering as msfilters
 from matchms import Spectrum
+from matchms.filtering.filter_order_and_default_pipelines import (
+    ALL_FILTERS, FILTER_FUNCTION_NAMES, PREDEFINED_PIPELINES)
 
 
 class SpectrumProcessor:
@@ -55,15 +56,15 @@ class SpectrumProcessor:
             filter function and the second element is a dictionary containing additional arguments for the function.
         """
         if isinstance(filter_spec, str):
-            if filter_spec not in FILTER_FUNCTIONS:
-                raise ValueError("Unknown filter type. Should be known filter name or function.")
-            filter_func = FILTER_FUNCTIONS[filter_spec]
+            if filter_spec not in FILTER_FUNCTION_NAMES:
+                raise ValueError(f"Unknown filter type: {filter_spec} Should be known filter name or function.")
+            filter_func = FILTER_FUNCTION_NAMES[filter_spec]
         elif isinstance(filter_spec, (tuple, list)):
             filter_name, filter_args = filter_spec
-            if filter_name not in FILTER_FUNCTIONS:
-                raise ValueError("Unknown filter type. Should be known filter name or function.")
-            filter_func = partial(FILTER_FUNCTIONS[filter_name], **filter_args)
-            filter_func.__name__ = FILTER_FUNCTIONS[filter_name].__name__
+            if filter_name not in FILTER_FUNCTION_NAMES:
+                raise ValueError(f"Unknown filter type: {filter_name} Should be known filter name or function.")
+            filter_func = partial(FILTER_FUNCTION_NAMES[filter_name], **filter_args)
+            filter_func.__name__ = FILTER_FUNCTION_NAMES[filter_name].__name__
         else:
             raise TypeError("filter_spec should be a string or a tuple or list")
 
@@ -194,94 +195,6 @@ class SpectrumProcessor:
         return summary_string
 
 
-# List all filters in a functionally working order
-ALL_FILTERS = [msfilters.make_charge_int,
-               msfilters.add_compound_name,
-               msfilters.derive_adduct_from_name,
-               msfilters.derive_formula_from_name,
-               msfilters.clean_compound_name,
-               msfilters.interpret_pepmass,
-               msfilters.add_precursor_mz,
-               msfilters.add_retention_index,
-               msfilters.add_retention_time,
-               msfilters.derive_ionmode,
-               msfilters.correct_charge,
-               # msfilters.derive_adduct_from_name,  # run again? Or improve those filters?
-               # msfilters.derive_formula_from_name,  # run again? Or improve those filters?
-               msfilters.require_precursor_mz,
-               msfilters.add_parent_mass,
-               msfilters.harmonize_undefined_inchikey,
-               msfilters.harmonize_undefined_inchi,
-               msfilters.harmonize_undefined_smiles,
-               msfilters.repair_inchi_inchikey_smiles,
-               msfilters.derive_smiles_from_inchi,
-               msfilters.repair_smiles_from_compound_name,
-               msfilters.derive_inchi_from_smiles,
-               msfilters.derive_inchikey_from_inchi,
-               msfilters.clean_adduct,
-               msfilters.repair_smiles_of_salts,
-               msfilters.repair_precursor_is_parent_mass,
-               msfilters.repair_parent_mass_is_mol_wt,
-               msfilters.repair_adduct_based_on_smiles,
-               msfilters.repair_parent_mass_match_smiles_wrapper,
-               msfilters.require_correct_ionmode,
-               msfilters.require_precursor_below_mz,
-               msfilters.require_valid_annotation,
-               msfilters.require_parent_mass_match_smiles,
-               msfilters.normalize_intensities,
-               msfilters.select_by_intensity,
-               msfilters.select_by_mz,
-               msfilters.select_by_relative_intensity,
-               msfilters.remove_peaks_around_precursor_mz,
-               msfilters.remove_peaks_outside_top_k,
-               msfilters.reduce_to_number_of_peaks,
-               msfilters.require_minimum_number_of_peaks,
-               msfilters.require_minimum_of_high_peaks,
-               msfilters.add_fingerprint,
-               msfilters.add_losses,
-              ]
-
-FILTER_FUNCTIONS = {x.__name__: x for x in ALL_FILTERS}
-
-MINIMAL_FILTERS = ["make_charge_int",
-                   "interpret_pepmass",
-                   "derive_ionmode",
-                   "correct_charge",
-                   ]
-BASIC_FILTERS = MINIMAL_FILTERS \
-    + ["add_compound_name",
-       "derive_adduct_from_name",
-       "derive_formula_from_name",
-       "clean_compound_name",
-       "add_precursor_mz",
-    ]
-DEFAULT_FILTERS = BASIC_FILTERS \
-    + ["require_precursor_mz",
-       "add_parent_mass",
-       "harmonize_undefined_inchikey",
-       "harmonize_undefined_inchi",
-       "harmonize_undefined_smiles",
-       "repair_inchi_inchikey_smiles",
-       "normalize_intensities",
-    ]
-FULLY_ANNOTATED_PROCESSING = DEFAULT_FILTERS \
-    + ["clean_adduct",
-       "derive_inchi_from_smiles",
-       "derive_smiles_from_inchi",
-       "derive_inchikey_from_inchi",
-       ("require_correct_ionmode", {"ion_mode_to_keep": "both"}),
-       ("require_parent_mass_match_smiles", {'mass_tolerance': 0.1}),
-       "require_valid_annotation",
-    ]
-
-PREDEFINED_PIPELINES = {
-    "minimal": MINIMAL_FILTERS,
-    "basic": BASIC_FILTERS,
-    "default": DEFAULT_FILTERS,
-    "fully_annotated": FULLY_ANNOTATED_PROCESSING,
-}
-
-
 class ProcessingReport:
     """Class to keep track of spectrum changes during filtering.
     """
diff --git a/matchms/filtering/__init__.py b/matchms/filtering/__init__.py
index 41cffdd5..9ef6b9e9 100644
--- a/matchms/filtering/__init__.py
+++ b/matchms/filtering/__init__.py
@@ -121,8 +121,8 @@ from .metadata_processing.require_parent_mass_match_smiles import \
 from .metadata_processing.require_precursor_below_mz import \
     require_precursor_below_mz
 from .metadata_processing.require_precursor_mz import require_precursor_mz
-from .metadata_processing.require_valid_annotation import \
-    require_valid_annotation
+from .metadata_processing.require_valid_annotation import (
+    repair_not_matching_annotation, require_valid_annotation)
 from .peak_processing.add_losses import add_losses
 from .peak_processing.normalize_intensities import normalize_intensities
 from .peak_processing.reduce_to_number_of_peaks import \
@@ -177,6 +177,7 @@ __all__ = [
     "repair_precursor_is_parent_mass",
     "repair_smiles_of_salts",
     "repair_smiles_from_compound_name",
+    "repair_not_matching_annotation",
     "require_valid_annotation",
     "require_parent_mass_match_smiles",
     "require_minimum_number_of_peaks",
diff --git a/matchms/filtering/filter_order_and_default_pipelines.py b/matchms/filtering/filter_order_and_default_pipelines.py
new file mode 100644
index 00000000..361f7850
--- /dev/null
+++ b/matchms/filtering/filter_order_and_default_pipelines.py
@@ -0,0 +1,88 @@
+from matchms import filtering as msfilters
+
+
+# List all filters in a functionally working order
+ALL_FILTERS = [msfilters.make_charge_int,
+               msfilters.add_compound_name,
+               msfilters.derive_adduct_from_name,
+               msfilters.derive_formula_from_name,
+               msfilters.clean_compound_name,
+               msfilters.interpret_pepmass,
+               msfilters.add_precursor_mz,
+               msfilters.add_retention_index,
+               msfilters.add_retention_time,
+               msfilters.derive_ionmode,
+               msfilters.correct_charge,
+               # msfilters.derive_adduct_from_name,  # run again? Or improve those filters?
+               # msfilters.derive_formula_from_name,  # run again? Or improve those filters?
+               msfilters.require_precursor_mz,
+               msfilters.add_parent_mass,
+               msfilters.harmonize_undefined_inchikey,
+               msfilters.harmonize_undefined_inchi,
+               msfilters.harmonize_undefined_smiles,
+               msfilters.repair_inchi_inchikey_smiles,
+               msfilters.derive_smiles_from_inchi,
+               msfilters.repair_smiles_from_compound_name,
+               msfilters.derive_inchi_from_smiles,
+               msfilters.derive_inchikey_from_inchi,
+               msfilters.clean_adduct,
+               msfilters.repair_smiles_of_salts,
+               msfilters.repair_precursor_is_parent_mass,
+               msfilters.repair_parent_mass_is_mol_wt,
+               msfilters.repair_adduct_based_on_smiles,
+               msfilters.repair_parent_mass_match_smiles_wrapper,
+               msfilters.repair_not_matching_annotation,
+               msfilters.require_valid_annotation,
+               msfilters.require_correct_ionmode,
+               msfilters.require_precursor_below_mz,
+               msfilters.require_parent_mass_match_smiles,
+               msfilters.normalize_intensities,
+               msfilters.select_by_intensity,
+               msfilters.select_by_mz,
+               msfilters.select_by_relative_intensity,
+               msfilters.remove_peaks_around_precursor_mz,
+               msfilters.remove_peaks_outside_top_k,
+               msfilters.reduce_to_number_of_peaks,
+               msfilters.require_minimum_number_of_peaks,
+               msfilters.require_minimum_of_high_peaks,
+               msfilters.add_fingerprint,
+               msfilters.add_losses,
+               ]
+FILTER_FUNCTION_NAMES = {x.__name__: x for x in ALL_FILTERS}
+MINIMAL_FILTERS = ["make_charge_int",
+                   "interpret_pepmass",
+                   "derive_ionmode",
+                   "correct_charge",
+                   ]
+BASIC_FILTERS = MINIMAL_FILTERS \
+                + ["add_compound_name",
+                   "derive_adduct_from_name",
+                   "derive_formula_from_name",
+                   "clean_compound_name",
+                   "add_precursor_mz",
+                   ]
+DEFAULT_FILTERS = BASIC_FILTERS \
+                  + ["require_precursor_mz",
+                     "add_parent_mass",
+                     "harmonize_undefined_inchikey",
+                     "harmonize_undefined_inchi",
+                     "harmonize_undefined_smiles",
+                     "repair_inchi_inchikey_smiles",
+                     "normalize_intensities",
+                     ]
+FULLY_ANNOTATED_PROCESSING = DEFAULT_FILTERS \
+                             + ["clean_adduct",
+                                "derive_inchi_from_smiles",
+                                "derive_smiles_from_inchi",
+                                "derive_inchikey_from_inchi",
+                                ("require_correct_ionmode", {"ion_mode_to_keep": "both"}),
+                                ("require_parent_mass_match_smiles", {'mass_tolerance': 0.1}),
+                                "repair_not_matching_annotation",
+                                "require_valid_annotation",
+                                ]
+PREDEFINED_PIPELINES = {
+    "minimal": MINIMAL_FILTERS,
+    "basic": BASIC_FILTERS,
+    "default": DEFAULT_FILTERS,
+    "fully_annotated": FULLY_ANNOTATED_PROCESSING,
+}
diff --git a/matchms/filtering/filter_utils/get_neutral_mass_from_smiles.py b/matchms/filtering/filter_utils/get_neutral_mass_from_smiles.py
index d0fb93c6..1a74d5fc 100644
--- a/matchms/filtering/filter_utils/get_neutral_mass_from_smiles.py
+++ b/matchms/filtering/filter_utils/get_neutral_mass_from_smiles.py
@@ -1,6 +1,11 @@
+import logging
+from typing import Optional
 from matchms.constants import PROTON_MASS
 
 
+logger = logging.getLogger("matchms")
+
+
 try:  # rdkit is not included in pip package
     from rdkit import Chem
     from rdkit.Chem import Descriptors
@@ -37,7 +42,6 @@ def get_monoisotopic_neutral_mass(smiles: str) -> float:
     return _get_neutral_mass(smiles, True)
 
 
-
 def get_molecular_weight_neutral_mass(smiles: str) -> float:
     """Get the (average) molecular weight for the isotopic distribution of the SMILES code.
 
@@ -53,7 +57,7 @@ def get_molecular_weight_neutral_mass(smiles: str) -> float:
     return _get_neutral_mass(smiles, False)
 
 
-def _get_neutral_mass(smiles:str, monoisotopic: bool) -> float:
+def _get_neutral_mass(smiles: str, monoisotopic: bool) -> Optional[float]:
     """Get neutral mass of molecule, either average or most abundant monoisotopic mass.
 
     Args:
@@ -69,6 +73,9 @@ def _get_neutral_mass(smiles:str, monoisotopic: bool) -> float:
     if not _has_rdkit:
         raise ImportError(rdkit_missing_message)
     mol = Chem.MolFromSmiles(smiles)
+    if mol is None:
+        logger.warning("No mass could be calculated for smiles: %s, since it is not a valid smiles.", smiles)
+        return None
     mass = Descriptors.ExactMolWt(mol) if monoisotopic else Descriptors.MolWt(mol)
     charge = sum(atom.GetFormalCharge() for atom in mol.GetAtoms())
     neutral_mass = mass + -charge * PROTON_MASS
diff --git a/matchms/filtering/filter_utils/smile_inchi_inchikey_conversions.py b/matchms/filtering/filter_utils/smile_inchi_inchikey_conversions.py
index 4a32b9d8..bff5e408 100644
--- a/matchms/filtering/filter_utils/smile_inchi_inchikey_conversions.py
+++ b/matchms/filtering/filter_utils/smile_inchi_inchikey_conversions.py
@@ -1,5 +1,6 @@
 import re
 from typing import Optional
+from matchms import Spectrum
 
 
 try:  # rdkit is not included in pip package
@@ -144,3 +145,16 @@ def is_valid_inchikey(inchikey: str) -> bool:
     if re.fullmatch(regexp, inchikey):
         return True
     return False
+
+
+def _check_fully_annotated(spectrum: Spectrum) -> bool:
+    """Combine multiple check functions.
+    Returns False if SMILES, InChIKey, or InChI are missing.
+    """
+    if not is_valid_smiles(spectrum.get("smiles")):
+        return False
+    if not is_valid_inchikey(spectrum.get("inchikey")):
+        return False
+    if not is_valid_inchi(spectrum.get("inchi")):
+        return False
+    return True
diff --git a/matchms/filtering/metadata_processing/repair_adduct_based_on_smiles.py b/matchms/filtering/metadata_processing/repair_adduct_based_on_smiles.py
index b577997a..f16f8e68 100644
--- a/matchms/filtering/metadata_processing/repair_adduct_based_on_smiles.py
+++ b/matchms/filtering/metadata_processing/repair_adduct_based_on_smiles.py
@@ -10,10 +10,30 @@ logger = logging.getLogger("matchms")
 
 
 def repair_adduct_based_on_smiles(spectrum_in: Spectrum,
-                                  mass_tolerance,
-                                  accept_parent_mass_is_mol_wt):
-    """If the parent mass is wrong due to a wrong of is derived from the precursor mz
-    To do this the charge and adduct are used"""
+                                  mass_tolerance: float,
+                                  accept_parent_mass_is_mol_wt: bool = True):
+    """
+    Corrects the adduct of a spectrum based on its SMILES representation and the precursor m/z.
+
+    Given a spectrum, this function tries to match the spectrum's parent mass, derived from its
+    precursor m/z and known adducts, to the neutral monoisotopic mass of the molecule derived
+    from its SMILES representation. If a match is found within a given mass tolerance, the
+    adduct and parent mass of the spectrum are updated.
+
+    Parameters:
+    ----------
+    spectrum_in : Spectrum
+        The input spectrum whose adduct needs to be repaired.
+
+    mass_tolerance : float
+        Maximum allowed mass difference between the calculated parent mass and the neutral
+        monoisotopic mass derived from the SMILES.
+
+    accept_parent_mass_is_mol_wt : bool, optional (default=True)
+        Allows the function to attempt repairing the spectrum's parent mass by assuming it
+        represents the molecule's weight. If True, further checks and corrections are made
+        using `repair_parent_mass_is_mol_wt`.
+    """
     if spectrum_in is None:
         return None
     changed_spectrum = spectrum_in.clone()
@@ -30,6 +50,8 @@ def repair_adduct_based_on_smiles(spectrum_in: Spectrum,
 
     adducts_df = load_known_adducts()
     smiles_mass = get_monoisotopic_neutral_mass(changed_spectrum.get("smiles"))
+    if smiles_mass is None:
+        return changed_spectrum
     parent_masses = (precursor_mz - adducts_df["correction_mass"]) / adducts_df["mass_multiplier"]
     mass_differences = abs(parent_masses-smiles_mass)
 
diff --git a/matchms/filtering/metadata_processing/repair_parent_mass_is_mol_wt.py b/matchms/filtering/metadata_processing/repair_parent_mass_is_mol_wt.py
index 747037d8..3a0826c6 100644
--- a/matchms/filtering/metadata_processing/repair_parent_mass_is_mol_wt.py
+++ b/matchms/filtering/metadata_processing/repair_parent_mass_is_mol_wt.py
@@ -27,8 +27,10 @@ def repair_parent_mass_is_mol_wt(spectrum_in: Spectrum, mass_tolerance: float):
     # Check if parent mass matches the smiles mass
     parent_mass = spectrum.get("parent_mass")
     smiles = spectrum.get("smiles")
-    smiles_mass = get_molecular_weight_neutral_mass(smiles)
-    mass_difference = parent_mass - smiles_mass
+    smiles_molecular_weight = get_molecular_weight_neutral_mass(smiles)
+    if smiles_molecular_weight is None:
+        return spectrum
+    mass_difference = parent_mass - smiles_molecular_weight
     if abs(mass_difference) < mass_tolerance:
         correct_mass = get_monoisotopic_neutral_mass(smiles)
         spectrum.set("parent_mass", correct_mass)
diff --git a/matchms/filtering/metadata_processing/repair_parent_mass_match_smiles_wrapper.py b/matchms/filtering/metadata_processing/repair_parent_mass_match_smiles_wrapper.py
index 30a1e81e..9647b277 100644
--- a/matchms/filtering/metadata_processing/repair_parent_mass_match_smiles_wrapper.py
+++ b/matchms/filtering/metadata_processing/repair_parent_mass_match_smiles_wrapper.py
@@ -6,34 +6,30 @@ from matchms.typing import SpectrumType
 from .repair_parent_mass_is_mol_wt import repair_parent_mass_is_mol_wt
 from .repair_precursor_is_parent_mass import repair_precursor_is_parent_mass
 from .repair_smiles_of_salts import repair_smiles_of_salts
-from .require_parent_mass_match_smiles import require_parent_mass_match_smiles
+from .require_parent_mass_match_smiles import \
+    _check_smiles_and_parent_mass_match
 
 
 logger = logging.getLogger("matchms")
 
 
-def repair_parent_mass_match_smiles_wrapper(spectrum_in: SpectrumType, mass_tolerance: float = 0.2) -> Optional[SpectrumType]:
+def repair_parent_mass_match_smiles_wrapper(spectrum_in: SpectrumType,
+                                            mass_tolerance: float = 0.2) -> Optional[SpectrumType]:
     """Wrapper function for repairing a mismatch between parent mass and smiles mass"""
     if spectrum_in is None:
         return None
     spectrum = spectrum_in.clone()
 
-    if require_parent_mass_match_smiles(spectrum, mass_tolerance) is not None:
-        return spectrum
-
-    spectrum = repair_smiles_of_salts(spectrum, mass_tolerance)
-    if require_parent_mass_match_smiles(spectrum, mass_tolerance) is not None:
-        return spectrum
-
-    spectrum = repair_precursor_is_parent_mass(spectrum, mass_tolerance)
-    if require_parent_mass_match_smiles(spectrum, mass_tolerance) is not None:
-        return spectrum
-
-    spectrum = repair_parent_mass_is_mol_wt(spectrum, mass_tolerance)
-    if require_parent_mass_match_smiles(spectrum, mass_tolerance) is not None:
-        return spectrum
-
-    spectrum = repair_adduct_based_on_smiles(spectrum, mass_tolerance, accept_parent_mass_is_mol_wt=True)
-    if require_parent_mass_match_smiles(spectrum, mass_tolerance) is not None:
-        return spectrum
+    filters_to_apply = [repair_smiles_of_salts,
+                        repair_precursor_is_parent_mass,
+                        repair_parent_mass_is_mol_wt,
+                        repair_adduct_based_on_smiles,
+                        ]
+    for filter_function in filters_to_apply:
+        if _check_smiles_and_parent_mass_match(smiles=spectrum.get("smiles"),
+                                               parent_mass=spectrum.get("parent_mass"),
+                                               mass_tolerance=mass_tolerance):
+            return spectrum
+        spectrum = filter_function(spectrum_in=spectrum,
+                                   mass_tolerance=mass_tolerance)
     return spectrum
diff --git a/matchms/filtering/metadata_processing/repair_precursor_is_parent_mass.py b/matchms/filtering/metadata_processing/repair_precursor_is_parent_mass.py
index 8478a0b2..05c22440 100644
--- a/matchms/filtering/metadata_processing/repair_precursor_is_parent_mass.py
+++ b/matchms/filtering/metadata_processing/repair_precursor_is_parent_mass.py
@@ -29,6 +29,8 @@ def repair_precursor_is_parent_mass(spectrum_in: Spectrum,
 
     smiles = spectrum.get("smiles")
     smiles_mass = get_monoisotopic_neutral_mass(smiles)
+    if smiles_mass is None:
+        return spectrum
     mass_difference = precursor_mz - smiles_mass
     if abs(mass_difference) < mass_tolerance:
         logger.info("Parent mass was changed from %s to %s", spectrum.get("parent_mass"), smiles_mass)
diff --git a/matchms/filtering/metadata_processing/repair_smiles_from_compound_name.py b/matchms/filtering/metadata_processing/repair_smiles_from_compound_name.py
index 426b8346..574fab3b 100644
--- a/matchms/filtering/metadata_processing/repair_smiles_from_compound_name.py
+++ b/matchms/filtering/metadata_processing/repair_smiles_from_compound_name.py
@@ -2,8 +2,8 @@ import logging
 import numpy as np
 import pandas as pd
 from matchms import Spectrum
-from matchms.filtering.filter_utils.smile_inchi_inchikey_conversions import (
-    is_valid_inchi, is_valid_inchikey, is_valid_smiles)
+from matchms.filtering.filter_utils.smile_inchi_inchikey_conversions import \
+    _check_fully_annotated
 
 
 logger = logging.getLogger("matchms")
@@ -63,19 +63,6 @@ def _load_compound_name_annotations(annotated_compound_names_file):
     return annotated_compound_names
 
 
-def _check_fully_annotated(spectrum: Spectrum) -> bool:
-    """Combine multiple check functions.
-    Returns False if SMILES, InChIKey, or InChI are missing.
-    """
-    if not is_valid_smiles(spectrum.get("smiles")):
-        return False
-    if not is_valid_inchikey(spectrum.get("inchikey")):
-        return False
-    if not is_valid_inchi(spectrum.get("inchi")):
-        return False
-    return True
-
-
 def _is_plausible_name(compound_name):
     """Simple check if it can be a compound name."""
     return isinstance(compound_name, str) and len(compound_name) > 4
diff --git a/matchms/filtering/metadata_processing/repair_smiles_of_salts.py b/matchms/filtering/metadata_processing/repair_smiles_of_salts.py
index 7f31c8f0..94321075 100644
--- a/matchms/filtering/metadata_processing/repair_smiles_of_salts.py
+++ b/matchms/filtering/metadata_processing/repair_smiles_of_salts.py
@@ -2,6 +2,8 @@ import itertools
 import logging
 from matchms.filtering.filter_utils.get_neutral_mass_from_smiles import \
     get_monoisotopic_neutral_mass
+from matchms.filtering.filter_utils.smile_inchi_inchikey_conversions import \
+    is_valid_smiles
 
 
 logger = logging.getLogger("matchms")
@@ -17,6 +19,12 @@ def repair_smiles_of_salts(spectrum_in,
     spectrum = spectrum_in.clone()
 
     smiles = spectrum.get("smiles")
+    if smiles is None:
+        return spectrum
+
+    if not is_valid_smiles(smiles):
+        logger.warning("No valid smiles, please run require_valid_annotation before")
+        return spectrum
     parent_mass = spectrum.get("parent_mass")
     possible_ion_combinations = _create_possible_ions(smiles)
     if not possible_ion_combinations:
diff --git a/matchms/filtering/metadata_processing/require_parent_mass_match_smiles.py b/matchms/filtering/metadata_processing/require_parent_mass_match_smiles.py
index 12e7ce1e..f1fcf9a4 100644
--- a/matchms/filtering/metadata_processing/require_parent_mass_match_smiles.py
+++ b/matchms/filtering/metadata_processing/require_parent_mass_match_smiles.py
@@ -30,10 +30,17 @@ def require_parent_mass_match_smiles(spectrum_in: SpectrumType,
 
     spectrum = spectrum_in.clone()
     # Check if parent mass matches the smiles mass
-    parent_mass = spectrum.get("parent_mass")
-    smiles = spectrum.get("smiles")
+    if _check_smiles_and_parent_mass_match(spectrum.get("smiles"), spectrum.get("parent_mass"), mass_tolerance):
+        return spectrum
+    return None
+
+
+def _check_smiles_and_parent_mass_match(smiles, parent_mass, mass_tolerance) -> bool:
+    """Returns True if smiles and parent mass are matching"""
     smiles_mass = get_monoisotopic_neutral_mass(smiles)
+    if smiles_mass is None:
+        return False
     mass_difference = parent_mass - smiles_mass
     if abs(mass_difference) < mass_tolerance:
-        return spectrum
-    return None
+        return True
+    return False
diff --git a/matchms/filtering/metadata_processing/require_valid_annotation.py b/matchms/filtering/metadata_processing/require_valid_annotation.py
index 20cd328b..0233f0b3 100644
--- a/matchms/filtering/metadata_processing/require_valid_annotation.py
+++ b/matchms/filtering/metadata_processing/require_valid_annotation.py
@@ -1,13 +1,63 @@
 import logging
 from matchms import Spectrum
 from matchms.filtering.filter_utils.smile_inchi_inchikey_conversions import (
-    convert_inchi_to_inchikey, convert_smiles_to_inchi, is_valid_inchi,
-    is_valid_inchikey, is_valid_smiles)
+    _check_fully_annotated, convert_inchi_to_inchikey, convert_inchi_to_smiles,
+    convert_smiles_to_inchi, is_valid_inchi, is_valid_inchikey,
+    is_valid_smiles)
+from matchms.filtering.metadata_processing.require_parent_mass_match_smiles import \
+    _check_smiles_and_parent_mass_match
 
 
 logger = logging.getLogger("matchms")
 
 
+def repair_not_matching_annotation(spectrum_in: Spectrum):
+    """When smiles and inchi do not match the annotation that matches parent mass will be kept"""
+    if spectrum_in is None:
+        return None
+    spectrum = spectrum_in.clone()
+    # Check if smiles, inchi and inchikey are valid
+    if _check_fully_annotated(spectrum):
+        logger.warning("First run derive inchi_from_smiles, derive_inchikey_from_inchi and derive_smiles_from_inchi")
+    smiles = spectrum.get("smiles")
+    inchi = spectrum.get("inchi")
+    inchikey = spectrum.get("inchikey")
+
+    # Check if smiles and inchi match
+    if convert_smiles_to_inchi(smiles) != inchi:
+        # There is a mismatch between smiles and inchi
+        parent_mass = spectrum.get("parent_mass")
+        smiles_correct = _check_smiles_and_parent_mass_match(smiles, parent_mass, 0.1)
+        inchi_correct = _check_smiles_and_parent_mass_match(convert_inchi_to_smiles(inchi), parent_mass, 0.1)
+        if smiles_correct and inchi_correct:
+            logger.warning("The smiles and inchi are not matching, but both match the parent mass. "
+                           "Smiles = %s, inchi = %s, inchikey = %s", smiles, inchi, inchikey)
+            return spectrum
+        if smiles_correct and not inchi_correct:
+            # repair the inchi from the smiles
+            new_inchi = convert_smiles_to_inchi(smiles)
+            spectrum.set("inchi", new_inchi)
+            logger.info("The inchi has been changed from %s to %s"
+                        "The new inchi matches the parent mass, while the old one did not", inchi, new_inchi)
+        else:
+            # repair the smiles from the inchi
+            new_smiles = convert_inchi_to_smiles(inchi)
+            spectrum.set("smiles", new_smiles)
+            logger.info("The smiles has been changed from %s to %s, to match the inchi. "
+                        "The new smiles matches the parent mass, while the old one did not", smiles, new_smiles)
+
+    # Check if the inchikey matches the inchi
+    if inchikey[:14] == convert_inchi_to_inchikey(spectrum.get("inchi"))[:14]:
+        # The inchi, smiles and inchikey all already matched
+        return spectrum
+    # The smiles and inchi (now) match, but the inchikey is still wrong
+    # Repair inchikey
+    new_inchikey = convert_inchi_to_inchikey(spectrum.get("inchi"))
+    logger.info("The inchikey has been changed from %s to %s", inchikey, new_inchikey)
+    spectrum.set("inchikey", new_inchikey)
+    return spectrum
+
+
 def require_valid_annotation(spectrum: Spectrum):
     """Removes spectra that are not fully annotated (correct and matching, smiles, inchi and inchikey)"""
     if spectrum is None:
@@ -24,28 +74,19 @@ def require_valid_annotation(spectrum: Spectrum):
     if not is_valid_inchi(inchi):
         logger.info("Removed spectrum since inchi is not valid. Incorrect inchi = %s", inchi)
         return None
-    if not _check_smiles_inchi_inchikey_match(spectrum):
+    if not _check_smiles_inchi_inchikey_match(smiles, inchi, inchikey):
+        logger.info("Removed spectrum since smiles, inchi and inchikey do not match. "
+                    "Smiles = %s, inchi = %s, inchikey = %s", smiles, inchi, inchikey)
         return None
     return spectrum
 
 
-def _check_smiles_inchi_inchikey_match(spectrum) -> bool:
-    """Checks if a spectrum"""
-    if spectrum is None:
-        return False
-    smiles = spectrum.get("smiles")
-    inchi = spectrum.get("inchi")
-    inchikey = spectrum.get("inchikey")
+def _check_smiles_inchi_inchikey_match(smiles, inchi, inchikey) -> bool:
+    """Checks if smiles inchi and inchikey match"""
     # check if inchi matches the inchikey
     if not inchikey[:14] == convert_inchi_to_inchikey(inchi)[:14]:
-        logger.warning("Removed spectrum since inchi and inchikey do not match. "
-                       "inchi = %s, inchikey = %s, expected_inchikey = %s",
-                       inchi, inchikey, convert_inchi_to_inchikey(inchi))
         return False
     # check if smiles matches the inchikey (first convert to inchi followed by converting to inchikey)
     if not inchikey[:14] == convert_inchi_to_inchikey(convert_smiles_to_inchi(smiles))[:14]:
-        logger.warning("Removed spectrum since smiles does not match the inchikey. "
-                       "inchikey = %s, smiles = %s, expected_inchikey = %s",
-                       inchikey, smiles, convert_inchi_to_inchikey(convert_smiles_to_inchi(smiles)))
         return False
     return True


Test patch:
diff --git a/tests/filtering/test_all_filter_order.py b/tests/filtering/test_all_filter_order.py
new file mode 100644
index 00000000..28a6dc6e
--- /dev/null
+++ b/tests/filtering/test_all_filter_order.py
@@ -0,0 +1,90 @@
+"""These tests are meant to check that certain conditions are maintained,
+when changing the ALL_FILTERS order in the future"""
+import ast
+import os
+from typing import Callable, List
+import pytest
+from matchms import filtering as msfilters
+from matchms.filtering.filter_order_and_default_pipelines import (
+    ALL_FILTERS, PREDEFINED_PIPELINES)
+from matchms.filtering.SpectrumProcessor import SpectrumProcessor
+
+
+REPAIR_PARENT_MASS_SMILES_FILTERS = \
+    [msfilters.repair_smiles_of_salts, msfilters.repair_precursor_is_parent_mass,
+     msfilters.repair_parent_mass_is_mol_wt, msfilters.repair_adduct_based_on_smiles,
+     msfilters.repair_parent_mass_match_smiles_wrapper, ]
+ANNOTATION_REPARATIONS = [msfilters.repair_inchi_inchikey_smiles, msfilters.derive_smiles_from_inchi,
+                          msfilters.repair_smiles_from_compound_name, msfilters.derive_inchi_from_smiles,
+                          msfilters.derive_inchikey_from_inchi, ]
+
+
+@pytest.mark.parametrize("early_filters, later_filters", [
+    [[msfilters.repair_not_matching_annotation], [msfilters.require_valid_annotation]],
+    [REPAIR_PARENT_MASS_SMILES_FILTERS, [msfilters.require_parent_mass_match_smiles]],
+    [ANNOTATION_REPARATIONS + [msfilters.clean_adduct], REPAIR_PARENT_MASS_SMILES_FILTERS],
+    [[msfilters.add_precursor_mz,], [msfilters.require_precursor_mz,]],
+])
+def test_all_filter_order(early_filters: List[Callable], later_filters: List[Callable]):
+    """Tests if early_filter is run before later_filter"""
+    for early_filter in early_filters:
+        for later_filter in later_filters:
+            for filter_index, filter_function in enumerate(ALL_FILTERS):
+                if early_filter == filter_function:
+                    early_filter_index = filter_index
+                if later_filter == filter_function:
+                    later_filter_index = filter_index
+            assert later_filter_index > early_filter_index, \
+                f"The filter {early_filter.__name__} should be before {later_filter.__name__}"
+
+
+def test_all_filters_is_complete():
+    """Checks that the global varible ALL_FILTERS contains all the available filters
+
+    This is important, since performing tests in the wrong order can make some filters useless.
+    """
+    def get_functions_from_file(file_path):
+        """Gets all python functions in a file"""
+        with open(file_path, 'r', encoding="utf-8") as file:
+            tree = ast.parse(file.read(), filename=file_path)
+        functions = []
+        for node in ast.walk(tree):
+            if isinstance(node, ast.FunctionDef):
+                functions.append(node.name)
+        return functions
+
+    current_dir = os.path.dirname(os.path.abspath(__file__))
+    filtering_directory = os.path.join(current_dir, "../../matchms/filtering")
+    directories_with_filters = ["metadata_processing",
+                                "peak_processing"]
+
+    all_filters = [filter.__name__ for filter in ALL_FILTERS]
+    list_of_filter_function_names = []
+    for directory_with_filters in directories_with_filters:
+        directory_with_filters = os.path.join(filtering_directory, directory_with_filters)
+        scripts = os.listdir(directory_with_filters)
+        for script in scripts:
+            # Remove __init__
+            if script[0] == "_":
+                break
+            if script[-3:] == ".py":
+                functions = get_functions_from_file(os.path.join(directory_with_filters, script))
+                for function in functions:
+                    if function[0] != "_":
+                        list_of_filter_function_names.append((script, function))
+    for script, filter_function in list_of_filter_function_names:
+        assert filter_function in all_filters, \
+            f"The function {filter_function} in the script {script} is not given in ALL_FILTERS, " \
+            f"this should be added to ensure a correct order of filter functions." \
+            f"If this function is not a filter add a _ before the function name"
+
+
+def test_all_filters_no_duplicates():
+    all_filters = [filter.__name__ for filter in ALL_FILTERS]
+    assert len(all_filters) == len(set(all_filters)), "One of the filters appears twice in ALL_FILTERS"
+
+
+def test_create_predefined_pipelines():
+    """Tests if all predefined pipelines can be run"""
+    for pipeline_name in PREDEFINED_PIPELINES:
+        SpectrumProcessor(pipeline_name)
diff --git a/tests/filtering/test_require_valid_annotation.py b/tests/filtering/test_require_valid_annotation.py
index 4888bdd9..2e2f776b 100644
--- a/tests/filtering/test_require_valid_annotation.py
+++ b/tests/filtering/test_require_valid_annotation.py
@@ -1,5 +1,6 @@
 import pytest
-from matchms.filtering import require_valid_annotation
+from matchms.filtering import (repair_not_matching_annotation,
+                               require_valid_annotation)
 from ..builder_Spectrum import SpectrumBuilder
 
 
@@ -11,7 +12,7 @@ from ..builder_Spectrum import SpectrumBuilder
     ("CCC", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "FDHFJXKRMIVNCQ-RRNMINROSA-N", False),
     ("CCC", "InChI=1S/C4H10/c1-3-4-2/h3-4H2,1-2H3", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N", False),
 ])
-def test_clean_compound_name(smile, inchi, inchikey, correct):
+def test_require_valid_annotation(smile, inchi, inchikey, correct):
     pytest.importorskip("rdkit")
     builder = SpectrumBuilder()
     spectrum_in = builder.with_metadata({"smiles": smile,
@@ -22,3 +23,43 @@ def test_clean_compound_name(smile, inchi, inchikey, correct):
         assert spectrum_out == spectrum_in
     else:
         assert spectrum_out is None
+
+
+@pytest.mark.parametrize("smile, inchi, inchikey, correct_inchikey", [
+    ("CCC", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N"), #Already correct
+    ("CCC", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWOOPSS-UHFFFAOYSA-N", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N"), #Typo
+])
+def test_repair_valid_annotation_repair_inchikey(smile, inchi, inchikey, correct_inchikey):
+    """Checks if the inchikey is repaired, when smile and inchi already match"""
+    builder = SpectrumBuilder()
+    spectrum_in = builder.with_metadata({"smiles": smile,
+                                         "inchi": inchi,
+                                         "inchikey": inchikey}).build()
+    spectrum_out = repair_not_matching_annotation(spectrum_in)
+    assert spectrum_out.get("inchikey") == correct_inchikey
+    assert spectrum_out.get("smiles") == spectrum_in.get("smiles")
+    assert spectrum_out.get("inchi") == spectrum_in.get("inchi")
+
+
+@pytest.mark.parametrize("smile, inchi, inchikey, parent_mass, correct_smiles, correct_inchi, correct_inchikey", [
+    ("CCC", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N", 100,
+     "CCC", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N"),  # Already correct
+    ("CC", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWOOPSS-UHFFFAOYSA-N", 44,  # smiles and inchikey wrong
+     "CCC", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N"),
+    ("CCC", "InChI=1S/C4H10/c1-3-4-2/h3-4H2,1-2H3", "ATUOYWHBWOOPSS-UHFFFAOYSA-N", 44,  # inchi wrong
+     "CCC", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N"),
+    ("C(=O)=O", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N", 44,  # Both match the parent mass
+     "C(=O)=O", "InChI=1S/C3H8/c1-3-2/h3H2,1-2H3", "ATUOYWHBWRKTHZ-UHFFFAOYSA-N"),  # So nothing should be changed
+])
+def test_repair_valid_annotation_repair_smiles_inchi(smile, inchi, inchikey, parent_mass,
+                                                     correct_smiles, correct_inchi, correct_inchikey):
+    # pylint: disable=too-many-arguments
+    builder = SpectrumBuilder()
+    spectrum_in = builder.with_metadata({"smiles": smile,
+                                         "inchi": inchi,
+                                         "inchikey": inchikey,
+                                         "parent_mass": parent_mass}).build()
+    spectrum_out = repair_not_matching_annotation(spectrum_in)
+    assert spectrum_out.get("inchikey") == correct_inchikey
+    assert spectrum_out.get("smiles") == correct_smiles
+    assert spectrum_out.get("inchi") == correct_inchi
diff --git a/tests/filtering/test_spectrum_processor.py b/tests/filtering/test_spectrum_processor.py
index ce7b9bd3..5c6ef7ed 100644
--- a/tests/filtering/test_spectrum_processor.py
+++ b/tests/filtering/test_spectrum_processor.py
@@ -1,9 +1,7 @@
-import ast
-import os
 import numpy as np
 import pytest
 from matchms import SpectrumProcessor
-from matchms.SpectrumProcessor import ALL_FILTERS, ProcessingReport
+from matchms.filtering.SpectrumProcessor import ProcessingReport
 from ..builder_Spectrum import SpectrumBuilder
 
 
@@ -177,49 +175,3 @@ def test_add_filter_with_matchms_filter(spectrums):
     assert filters[-1].__name__ == "require_correct_ionmode"
     spectrums, _ = processor.process_spectrums(spectrums, create_report=True)
     assert not spectrums, "Expected to be empty list"
-
-
-def test_all_filters_is_complete():
-    """Checks that the global varible ALL_FILTERS contains all the available filters
-
-    This is important, since performing tests in the wrong order can make some filters useless.
-    """
-    def get_functions_from_file(file_path):
-        """Gets all python functions in a file"""
-        with open(file_path, 'r', encoding="utf-8") as file:
-            tree = ast.parse(file.read(), filename=file_path)
-        functions = []
-        for node in ast.walk(tree):
-            if isinstance(node, ast.FunctionDef):
-                functions.append(node.name)
-        return functions
-
-    current_dir = os.path.dirname(os.path.abspath(__file__))
-    filtering_directory = os.path.join(current_dir, "../../matchms/filtering")
-    directories_with_filters = ["metadata_processing",
-                                "peak_processing"]
-
-    all_filters = [filter.__name__ for filter in ALL_FILTERS]
-    list_of_filter_function_names = []
-    for directory_with_filters in directories_with_filters:
-        directory_with_filters = os.path.join(filtering_directory, directory_with_filters)
-        scripts = os.listdir(directory_with_filters)
-        for script in scripts:
-            # Remove __init__
-            if script[0] == "_":
-                break
-            if script[-3:] == ".py":
-                functions = get_functions_from_file(os.path.join(directory_with_filters, script))
-                for function in functions:
-                    if function[0] != "_":
-                        list_of_filter_function_names.append((script, function))
-    for script, filter_function in list_of_filter_function_names:
-        assert filter_function in all_filters, \
-            f"The function {filter_function} in the script {script} is not given in ALL_FILTERS, " \
-            f"this should be added to ensure a correct order of filter functions." \
-            f"If this function is not a filter add a _ before the function name"
-
-
-def test_all_filters_no_duplicates():
-    all_filters = [filter.__name__ for filter in ALL_FILTERS]
-    assert len(all_filters) == len(set(all_filters)), "One of the filters appears twice in ALL_FILTERS"