# Path: guacamol/utils/chemistry.py
# def canonicalize(smiles: str, include_stereocenters=True) -> Optional[str]:
#     """
#     Canonicalize the SMILES strings with RDKit.
# 
#     The algorithm is detailed under https://pubs.acs.org/doi/full/10.1021/acs.jcim.5b00543
# 
#     Args:
#         smiles: SMILES string to canonicalize
#         include_stereocenters: whether to keep the stereochemical information in the canonical SMILES string
# 
#     Returns:
#         Canonicalized SMILES string, None if the molecule is invalid.
#     """
# 
#     mol = Chem.MolFromSmiles(smiles)
# 
#     if mol is not None:
#         return Chem.MolToSmiles(mol, isomericSmiles=include_stereocenters)
#     else:
#         return None
# 
# def canonicalize_list(smiles_list: Iterable[str], include_stereocenters=True) -> List[str]:
#     """
#     Canonicalize a list of smiles. Filters out repetitions and removes corrupted molecules.
# 
#     Args:
#         smiles_list: molecules as SMILES strings
#         include_stereocenters: whether to keep the stereochemical information in the canonical SMILES strings
# 
#     Returns:
#         The canonicalized and filtered input smiles.
#     """
# 
#     canonicalized_smiles = [canonicalize(smiles, include_stereocenters) for smiles in smiles_list]
# 
#     # Remove None elements
#     canonicalized_smiles = [s for s in canonicalized_smiles if s is not None]
# 
#     return remove_duplicates(canonicalized_smiles)
# 
# def is_valid(smiles: str):
#     """
#     Verifies whether a SMILES string corresponds to a valid molecule.
# 
#     Args:
#         smiles: SMILES string
# 
#     Returns:
#         True if the SMILES strings corresponds to a valid, non-empty molecule.
#     """
# 
#     mol = Chem.MolFromSmiles(smiles)
# 
#     return smiles != '' and mol is not None and mol.GetNumAtoms() > 0
# 
# def calculate_internal_pairwise_similarities(smiles_list: Collection[str]) -> np.ndarray:
#     """
#     Computes the pairwise similarities of the provided list of smiles against itself.
# 
#     Returns:
#         Symmetric matrix of pairwise similarities. Diagonal is set to zero.
#     """
#     if len(smiles_list) > 10000:
#         logger.warning(f'Calculating internal similarity on large set of '
#                        f'SMILES strings ({len(smiles_list)})')
# 
#     mols = get_mols(smiles_list)
#     fps = get_fingerprints(mols)
#     nfps = len(fps)
# 
#     similarities = np.zeros((nfps, nfps))
# 
#     for i in range(1, nfps):
#         sims = DataStructs.BulkTanimotoSimilarity(fps[i], fps[:i])
#         similarities[i, :i] = sims
#         similarities[:i, i] = sims
# 
#     return similarities
# 
# def calculate_pairwise_similarities(smiles_list1: List[str], smiles_list2: List[str]) -> np.ndarray:
#     """
#     Computes the pairwise ECFP4 tanimoto similarity of the two smiles containers.
# 
#     Returns:
#         Pairwise similarity matrix as np.ndarray
#     """
#     if len(smiles_list1) > 10000 or len(smiles_list2) > 10000:
#         logger.warning(f'Calculating similarity between large sets of '
#                        f'SMILES strings ({len(smiles_list1)} x {len(smiles_list2)})')
# 
#     mols1 = get_mols(smiles_list1)
#     fps1 = get_fingerprints(mols1)
# 
#     mols2 = get_mols(smiles_list2)
#     fps2 = get_fingerprints(mols2)
# 
#     similarities = []
# 
#     for fp1 in fps1:
#         sims = DataStructs.BulkTanimotoSimilarity(fp1, fps2)
# 
#         similarities.append(sims)
# 
#     return np.array(similarities)
# 
# def parse_molecular_formula(formula: str) -> List[Tuple[str, int]]:
#     """
#     Parse a molecular formulat to get the element types and counts.
# 
#     Args:
#         formula: molecular formula, f.i. "C8H3F3Br"
# 
#     Returns:
#         A list of tuples containing element types and number of occurrences.
#     """
#     matches = re.findall(r'([A-Z][a-z]*)(\d*)', formula)
# 
#     # Convert matches to the required format
#     results = []
#     for match in matches:
#         # convert count to an integer, and set it to 1 if the count is not visible in the molecular formula
#         count = 1 if not match[1] else int(match[1])
#         results.append((match[0], count))
# 
#     return results


from guacamol.utils.chemistry import canonicalize, canonicalize_list, is_valid, \
    calculate_internal_pairwise_similarities, calculate_pairwise_similarities, parse_molecular_formula


def test_validity_empty_molecule():
    smiles = ''
    assert not is_valid(smiles)


def test_validity_incorrect_syntax():
    smiles = 'CCCincorrectsyntaxCCC'

# Path: guacamol/utils/chemistry.py
# def canonicalize(smiles: str, include_stereocenters=True) -> Optional[str]:
#     """
#     Canonicalize the SMILES strings with RDKit.
# 
#     The algorithm is detailed under https://pubs.acs.org/doi/full/10.1021/acs.jcim.5b00543
# 
#     Args:
#         smiles: SMILES string to canonicalize
#         include_stereocenters: whether to keep the stereochemical information in the canonical SMILES string
# 
#     Returns:
#         Canonicalized SMILES string, None if the molecule is invalid.
#     """
# 
#     mol = Chem.MolFromSmiles(smiles)
# 
#     if mol is not None:
#         return Chem.MolToSmiles(mol, isomericSmiles=include_stereocenters)
#     else:
#         return None
# 
# def canonicalize_list(smiles_list: Iterable[str], include_stereocenters=True) -> List[str]:
#     """
#     Canonicalize a list of smiles. Filters out repetitions and removes corrupted molecules.
# 
#     Args:
#         smiles_list: molecules as SMILES strings
#         include_stereocenters: whether to keep the stereochemical information in the canonical SMILES strings
# 
#     Returns:
#         The canonicalized and filtered input smiles.
#     """
# 
#     canonicalized_smiles = [canonicalize(smiles, include_stereocenters) for smiles in smiles_list]
# 
#     # Remove None elements
#     canonicalized_smiles = [s for s in canonicalized_smiles if s is not None]
# 
#     return remove_duplicates(canonicalized_smiles)
# 
# def is_valid(smiles: str):
#     """
#     Verifies whether a SMILES string corresponds to a valid molecule.
# 
#     Args:
#         smiles: SMILES string
# 
#     Returns:
#         True if the SMILES strings corresponds to a valid, non-empty molecule.
#     """
# 
#     mol = Chem.MolFromSmiles(smiles)
# 
#     return smiles != '' and mol is not None and mol.GetNumAtoms() > 0
# 
# def calculate_internal_pairwise_similarities(smiles_list: Collection[str]) -> np.ndarray:
#     """
#     Computes the pairwise similarities of the provided list of smiles against itself.
# 
#     Returns:
#         Symmetric matrix of pairwise similarities. Diagonal is set to zero.
#     """
#     if len(smiles_list) > 10000:
#         logger.warning(f'Calculating internal similarity on large set of '
#                        f'SMILES strings ({len(smiles_list)})')
# 
#     mols = get_mols(smiles_list)
#     fps = get_fingerprints(mols)
#     nfps = len(fps)
# 
#     similarities = np.zeros((nfps, nfps))
# 
#     for i in range(1, nfps):
#         sims = DataStructs.BulkTanimotoSimilarity(fps[i], fps[:i])
#         similarities[i, :i] = sims
#         similarities[:i, i] = sims
# 
#     return similarities
# 
# def calculate_pairwise_similarities(smiles_list1: List[str], smiles_list2: List[str]) -> np.ndarray:
#     """
#     Computes the pairwise ECFP4 tanimoto similarity of the two smiles containers.
# 
#     Returns:
#         Pairwise similarity matrix as np.ndarray
#     """
#     if len(smiles_list1) > 10000 or len(smiles_list2) > 10000:
#         logger.warning(f'Calculating similarity between large sets of '
#                        f'SMILES strings ({len(smiles_list1)} x {len(smiles_list2)})')
# 
#     mols1 = get_mols(smiles_list1)
#     fps1 = get_fingerprints(mols1)
# 
#     mols2 = get_mols(smiles_list2)
#     fps2 = get_fingerprints(mols2)
# 
#     similarities = []
# 
#     for fp1 in fps1:
#         sims = DataStructs.BulkTanimotoSimilarity(fp1, fps2)
# 
#         similarities.append(sims)
# 
#     return np.array(similarities)
# 
# def parse_molecular_formula(formula: str) -> List[Tuple[str, int]]:
#     """
#     Parse a molecular formulat to get the element types and counts.
# 
#     Args:
#         formula: molecular formula, f.i. "C8H3F3Br"
# 
#     Returns:
#         A list of tuples containing element types and number of occurrences.
#     """
#     matches = re.findall(r'([A-Z][a-z]*)(\d*)', formula)
# 
#     # Convert matches to the required format
#     results = []
#     for match in matches:
#         # convert count to an integer, and set it to 1 if the count is not visible in the molecular formula
#         count = 1 if not match[1] else int(match[1])
#         results.append((match[0], count))
# 
#     return results


# Path: tests/utils/test_chemistry.py
from guacamol.utils.chemistry import canonicalize, canonicalize_list, is_valid, \
    calculate_internal_pairwise_similarities, calculate_pairwise_similarities, parse_molecular_formula



def test_validity_empty_molecule():
    smiles = ''
    assert not is_valid(smiles)


def test_validity_incorrect_syntax():
    smiles = 'CCCincorrectsyntaxCCC'

    assert not is_valid(smiles)