Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v6
- name: Initialize
uses: github/codeql-action/init@v2
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish_pypi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: Build and publish to pypi
uses: JRubics/poetry-publish@v1.17
uses: JRubics/poetry-publish@v2.1
with:
pypi_token: ${{ secrets.PYPI_API_TOKEN }}
4 changes: 2 additions & 2 deletions .github/workflows/test-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ jobs:
max-parallel: 5

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v3
uses: actions/setup-python@v6
with:
python-version: 3.12
- name: Install dependencies
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
### Added
- Added `smiles_to_inchi`, `smiles_to_inchikey`, and `inchi_to_inchikey` conversions to the RDKit converter [#179](https://github.com/RECETOX/MSMetaEnhancer/pull/179)

## [0.5.1] - 2026-05-07
### Added
- Added high-level functions also for canonical smiles [#178](https://github.com/RECETOX/MSMetaEnhancer/pull/178)
Expand Down
47 changes: 46 additions & 1 deletion MSMetaEnhancer/libs/converters/compute/RDKit.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import re
from rdkit.Chem.Descriptors import ExactMolWt
from rdkit.Chem import MolFromSmiles, MolToSmiles
from rdkit.Chem.inchi import MolFromInchi
from rdkit.Chem.inchi import MolFromInchi, MolToInchi, InchiToInchiKey
from rdkit.Chem.rdMolDescriptors import CalcMolFormula
from rdkit.Chem import Atom

Expand All @@ -23,6 +23,10 @@ def __init__(self):
("isomeric_smiles", "mw", "from_smiles"),
("canonical_smiles", "formula", "smiles_to_formula"),
("isomeric_smiles", "formula", "smiles_to_formula"),
("canonical_smiles", "inchi", "smiles_to_inchi"),
("isomeric_smiles", "inchi", "smiles_to_inchi"),
("canonical_smiles", "inchikey", "smiles_to_inchikey"),
("isomeric_smiles", "inchikey", "smiles_to_inchikey"),
]
self.create_top_level_conversion_methods(conversions, asynch=False)

Expand Down Expand Up @@ -106,3 +110,44 @@ def inchi_to_formula(self, inchi: str) -> dict:
return {"formula": ""}
formula = CalcMolFormula(mol)
return {"formula": formula}

def smiles_to_inchi(self, smiles: str) -> dict:
"""
Compute InChI from SMILES.

:param smiles: given SMILES
:return: computed InChI
"""
mol = MolFromSmiles(smiles)
if mol is None:
return {"inchi": ""}
inchi = MolToInchi(mol)
return {"inchi": inchi}

def smiles_to_inchikey(self, smiles: str) -> dict:
"""
Compute InChIKey from SMILES.

:param smiles: given SMILES
:return: computed InChIKey
"""
mol = MolFromSmiles(smiles)
if mol is None:
return {"inchikey": ""}
inchi = MolToInchi(mol)
if not inchi:
return {"inchikey": ""}
inchikey = InchiToInchiKey(inchi)
return {"inchikey": inchikey}

def inchi_to_inchikey(self, inchi: str) -> dict:
"""
Compute InChIKey from InChI.

:param inchi: given InChI
:return: computed InChIKey
"""
if not inchi:
return {"inchikey": ""}
inchikey = InchiToInchiKey(inchi)
return {"inchikey": inchikey}
17 changes: 14 additions & 3 deletions galaxy/generate_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,31 @@
# this add to path the home dir, so it can be called from anywhere
sys.path.append(os.path.split(sys.path[0])[0])

from MSMetaEnhancer.libs.converters.web import CTS, CIR, IDSM, PubChem, BridgeDb
from MSMetaEnhancer.libs.converters.compute import RDKit
from MSMetaEnhancer.libs.utils.ConverterBuilder import ConverterBuilder

from MSMetaEnhancer.libs.converters.web import __all__ as web_converters
from MSMetaEnhancer.libs.converters.compute import __all__ as compute_converters


def generate_options():
ConverterBuilder.register([CTS, CIR, IDSM, PubChem, BridgeDb, RDKit])

jobs = []
converters = web_converters + compute_converters
built_converters, built_web_converters = ConverterBuilder().build_converters(

builder = ConverterBuilder()
builder.validate_converters(converters)
built_compute_converters, built_web_converters = builder.build_converters(
None, converters
)

for converter in built_converters:
jobs += built_converters[converter].get_conversion_functions()
for converter in built_compute_converters.values():
jobs += converter.get_conversion_functions()

for converter in built_web_converters.values():
jobs += converter.get_conversion_functions()

for job in jobs:
print(
Expand Down
3 changes: 3 additions & 0 deletions tests/test_CTS.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
import pytest

from MSMetaEnhancer.libs.converters.web import CTS
from MSMetaEnhancer.libs.utils.Errors import UnknownResponse
from tests.utils import wrap_with_session


@pytest.mark.dependency()
@pytest.mark.xfail(raises=UnknownResponse)
def test_service_available():
asyncio.run(wrap_with_session(CTS, "casno_to_inchikey", ["7783-89-3"]))



@pytest.mark.dependency(depends=["test_service_available"])
@pytest.mark.parametrize("value, size", [["7783-89-3", 1], ["7783893", 0]])
def test_format(value, size):
Expand Down
3 changes: 3 additions & 0 deletions tests/test_PubChem.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
from MSMetaEnhancer.libs.converters.web import PubChem
from frozendict import frozendict

from MSMetaEnhancer.libs.utils.Errors import UnknownResponse
from tests.utils import wrap_with_session


INCHI = "InChI=1S/C11H8FNO3/c1-13-6-9(10(14)16-11(13)15)7-2-4-8(12)5-3-7/h2-6H,1H3"


@pytest.mark.dependency()
@pytest.mark.xfail(raises=UnknownResponse)
def test_service_available():
asyncio.run(wrap_with_session(PubChem, "inchi_to_inchikey", [INCHI]))

Expand Down Expand Up @@ -72,6 +74,7 @@ def test_parse_attributes(response, expected):
assert actual == expected


@pytest.mark.dependency(depends=["test_service_available"])
def test_convert_inchikey_to_inchi():
inchikey = "OHCNQFYTLLGNOE-UHFFFAOYSA-N"
expected = "InChI=1S/C5H13NSi/c1-7(2,3)6-4-5-6/h4-5H2,1-3H3"
Expand Down
14 changes: 14 additions & 0 deletions tests/test_rdkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
INCHI = "InChI=1S/C19H28O2/c1-18-9-7-13(20)11-12(18)3-4-14-15-5-6-17(21)19(15,2)10-8-16(14)18/h11,14-17,21H,3-10H2,1-2H3/t14-,15-,16-,17-,18-,19-/m0/s1"
CANONICAL_SMILES = "CC12CCC(=O)C=C1CCC1C2CCC2(C)C(O)CCC12"
ISOMERIC_SMILES = "C[C@]12CC[C@H]3[C@@H](CCC4=CC(=O)CC[C@@]43C)[C@@H]1CC[C@@H]2O"
CANONICAL_INCHI = "InChI=1S/C19H28O2/c1-18-9-7-13(20)11-12(18)3-4-14-15-5-6-17(21)19(15,2)10-8-16(14)18/h11,14-17,21H,3-10H2,1-2H3"
INCHIKEY = "MUMGGOZAMZWBJJ-DYKIIFRCSA-N"
CANONICAL_INCHIKEY = "MUMGGOZAMZWBJJ-UHFFFAOYSA-N"


@pytest.mark.parametrize(
Expand All @@ -23,6 +26,17 @@
["canonical_smiles_to_formula", CANONICAL_SMILES, {"formula": "C19H28O2"}],
["isomeric_smiles_to_formula", ISOMERIC_SMILES, {"formula": "C19H28O2"}],
["inchi_to_formula", INCHI, {"formula": "C19H28O2"}],
["smiles_to_inchi", CANONICAL_SMILES, {"inchi": CANONICAL_INCHI}],
["canonical_smiles_to_inchi", CANONICAL_SMILES, {"inchi": CANONICAL_INCHI}],
["isomeric_smiles_to_inchi", ISOMERIC_SMILES, {"inchi": INCHI}],
["smiles_to_inchikey", CANONICAL_SMILES, {"inchikey": CANONICAL_INCHIKEY}],
[
"canonical_smiles_to_inchikey",
CANONICAL_SMILES,
{"inchikey": CANONICAL_INCHIKEY},
],
["isomeric_smiles_to_inchikey", ISOMERIC_SMILES, {"inchikey": INCHIKEY}],
["inchi_to_inchikey", INCHI, {"inchikey": INCHIKEY}],
],
)
def test_convert_methods(method, input, expected):
Expand Down