Skip to main content

HARMONSMILE: Harmonize SMILES Strings for Cheminformatics and Machine Learning

License: LGPL v3 Version PyPI Python Docs


Description

HARMONSMILE solves a common problem in cheminformatics: SMILES strings for the same molecule look different depending on the source (PubChem, ChEMBL, COCONUT, in-house databases). This inconsistency breaks comparisons, deduplication, and machine learning pipelines that expect a uniform molecular representation.

It is intended for computational chemists, cheminformatics researchers, ML practitioners preparing molecular datasets, and maintainers integrating PubChem, ChEMBL, and in-house sources.


Purpose

The primary objective of HARMONSMILE is to automate the preparation, standardization, and harmonization of molecular structure tables for cheminformatics workflows and machine learning applications within the computational drug discovery pipeline.

The platform enables:

  • Source-aware molecular table preparation: Ingests molecular identifiers or SMILES from PubChem, ChEMBL, and independent tabular datasets while preserving source traceability.
  • Deterministic identifier handling: Uses robust, alias-aware input detection for PubChem CIDs and emits a canonical PubChem_CID output column for downstream interoperability.
  • RDKit canonicalization: Generates SMILES_RDKit as a canonical/isomeric/Kekulé RDKit representation, preserving compatibility with workflows that use Kekulized SMILES for deduplication or comparison.
  • SMILES harmonization: Generates SMILES_Harmonized as a canonical/isomeric/aromatic representation after controlled RDKit-native standardization and harmonization.
  • Auditable status reporting: Reports harmonization outcomes through SMILES_Harmonization_Status and SMILES_Harmonization_Message, distinguishing successful harmonization, controlled transformations, unsupported ambiguous structures, and failures.
  • Cross-source comparison: Preserves structural bridge fields such as InChI and InChIKey to support comparison across PubChem, ChEMBL, and independent molecular databases.

SMILES Column Contract

HARMONSMILE exposes three universal SMILES representations in pipeline outputs:

  • SMILES: source/input SMILES. This is the value used as input for RDKit canonicalization and lab harmonization.
  • SMILES_RDKit: RDKit canonical + isomeric + Kekulized representation, produced by RDKitStandardizer.to_iso_kek(SMILES). This column is preserved for compatibility with v0.2.5. It is not a full chemical harmonization layer and does not intentionally desalt, neutralize, reionize, or canonicalize tautomers.
  • SMILES_Harmonized: lab-harmonized representation, produced by RDKitStandardizer.to_lab_harmonized(SMILES). It uses an RDKit-native MolStandardize policy with validation before automatic modification, controlled parent generation for simple salts/counterions, normalization, uncharging, reionization, optional tautomer canonicalization, and final canonical/isomeric/aromatic serialization.

SMILES_Harmonized is intended for database harmonization, deduplication, and cross-source matching. It is not guaranteed to represent the most stable, most abundant, pH-specific, or biologically active tautomer. HARMONSMILE does not export tautomer ensembles; it stores one canonical harmonized representation per input row. Source traceability is preserved through SMILES and SMILES_RDKit.

Rows are not dropped when harmonization fails. Instead, the result is carried in:

  • SMILES_Harmonization_Status: short filterable status returned by the harmonization engine: ok, ok_with_warnings, unsupported, or failed.
  • SMILES_Harmonization_Message: short auditable message for warnings, unsupported structures, or failures; empty/None for successful ok rows.

Some sources may also provide source-specific SMILES columns. For example, ConnectivitySMILES is a PubChem-provided connectivity SMILES column preserved when available; it is not generated by HARMONSMILE and is not present for all sources.


Installation

For package users

Create and activate a Python environment:

conda create -n harmonsmile_env python=3.11
conda activate harmonsmile_env

Install HARMONSMILE from PyPI:

pip install harmonsmile

RDKit (rdkit>=2022.09) is a required runtime dependency and is installed automatically as part of the package dependencies.

For contributors and developers

Clone the repository and install in editable mode with development dependencies:

git clone https://github.com/NanoBiostructuresRG/harmonsmile.git
cd harmonsmile
conda create -n harmonsmile_env python=3.11
conda activate harmonsmile_env
python -m pip install -e ".[dev]"

To build the documentation locally, install the docs extra as well:

python -m pip install -e ".[dev,docs]"
mkdocs serve

Quick Start

This quickstart walks through the entry points of HARMONSMILE: standardizing a single SMILES string in memory, and running the three pipelines — two identifier-driven (PubChem, ChEMBL) and one for any table that already contains SMILES. Each pipeline reads an input table, resolves and harmonizes structures, and returns a pandas.DataFrame carrying the SMILES column contract described above.

Example data. The commands below use the datasets in examples/, which ship with the repository but not with the PyPI wheel. To run them as written, clone the repository and work from its root:

git clone https://github.com/NanoBiostructuresRG/harmonsmile.git
cd harmonsmile

To use your own data instead, point input_path at any CSV, TSV, TXT, XLSX, XLSM, or XLS file with the columns listed under Input Format.

Python API

Standardize a single SMILES string, without any input file. The three methods show the difference between the compatibility layer and the harmonization layer:

from harmonsmile import RDKitStandardizer

std = RDKitStandardizer()
print(std.to_iso_kek("c1ccccc1"))    # 'C1=CC=CC=C1'  canonical + isomeric + Kekulized
print(std.to_conn_kek("c1ccccc1"))   # 'C1=CC=CC=C1'  connectivity only, no stereochemistry

result = std.to_lab_harmonized("c1ccccc1")
print(result.value)                  # 'c1ccccc1'     lab-harmonized, aromatic
print(result.status)                 # 'ok'

to_lab_harmonized returns a HarmonizationResult with value, status, error, and warning fields, rather than a bare string.

Fetch properties from PubChem and harmonize. The input needs a CID column; PubChem_CID is canonical, and PubChem CID, PubChemCID, and CID are accepted as aliases:

from harmonsmile import PubChemIngest, PubChemConfig, save_table

cfg = PubChemConfig(
    input_path="examples/example_pubchem.csv",   # columns: id, PubChem_CID
)
df = PubChemIngest(cfg).run()
save_table(df, "results/example_pubchem_harmonized.csv")

Fetch properties from ChEMBL and harmonize:

from harmonsmile import ChEMBLIngest, ChEMBLConfig, save_table

cfg = ChEMBLConfig(
    input_path="examples/example_chembl.csv",    # columns: id, ChEMBL ID
)
df = ChEMBLIngest(cfg).run()
save_table(df, "results/example_chembl_harmonized.csv")

Harmonize any table that already contains SMILES (COCONUT, in-house, etc.). The example file is tab-delimited, and the SMILES column may carry any name:

from harmonsmile import SMILESPrep, SMILESConfig, save_table

cfg = SMILESConfig(
    input_path="examples/example_smiles.txt",    # columns: id, name, SMILES
    smiles_col="SMILES",
)
df = SMILESPrep(cfg).run()
save_table(df, "results/example_smiles_harmonized.csv")

Pipeline .run() methods return a DataFrame and never write to disk. Persistence is explicit through save_table(df, path), which always writes CSV.

Command-Line Interface

The CLI covers the same pipelines and writes output files directly:

# PubChem batch
harmonsmile --pubchem-in  examples/example_pubchem.csv \
            --pubchem-out results/example_pubchem_harmonized.csv

# ChEMBL batch
harmonsmile --chembl-in  examples/example_chembl.csv \
            --chembl-out results/example_chembl_harmonized.csv

# SMILES batch (COCONUT, in-house, etc.)
harmonsmile --smiles-in  examples/example_smiles.txt --smiles-col SMILES \
            --smiles-out results/example_smiles_harmonized.csv

# Several pipelines in one call
harmonsmile \
  --pubchem-in  examples/example_pubchem.csv \
  --pubchem-out results/example_pubchem_harmonized.csv \
  --smiles-in   examples/example_smiles.txt --smiles-col SMILES \
  --smiles-out  results/example_smiles_harmonized.csv

# Single entry - fetch and harmonize one compound by identifier
# Output is written to results/ automatically
harmonsmile --pubchem-cid 2723949
harmonsmile --chembl-id CHEMBL294199

# Check version
harmonsmile --version

When the identifier column carries a non-standard name, declare it explicitly:

harmonsmile --pubchem-in  data/my_table.csv --pubchem-cidcol "compound_cid" \
            --pubchem-out results/out.csv

harmonsmile --chembl-in  data/my_table.csv --chembl-idcol "chembl_identifier" \
            --chembl-out results/out.csv

Also available as a module:

python -m harmonsmile --pubchem-in  examples/example_pubchem.csv \
                      --pubchem-out results/out.csv

Run harmonsmile --help for the full argument reference.

Next steps

  • SMILES Column Contract — what each output column means and how to filter rows on harmonization status.
  • Usage guide — longer worked examples.
  • API reference — full signatures for every public class and function.
  • examples/fetch_pubchem.py and examples/fetch_chembl.py — build larger input tables from a free-text query before running a pipeline.

Pipelines

Pipeline Config Source Input API
PubChemIngest PubChemConfig PubChem Table with a PubChem_CID column REST (public)
ChEMBLIngest ChEMBLConfig ChEMBL Table with a ChEMBL ID column REST (public)
SMILESPrep SMILESConfig Any Table with any SMILES column Local file

All pipelines preserve the source SMILES, append SMILES_RDKit, and append the lab harmonization columns SMILES_Harmonized, SMILES_Harmonization_Status, and SMILES_Harmonization_Message. Pipeline .run() methods return a pandas.DataFrame and do not write files. Use save_table(df, path) to persist results from Python, or the CLI --*-out options.


Input Format

Pipeline Required columns Column option
PubChemIngest id (optional), PubChem_CID cid_col / --pubchem-cidcol
ChEMBLIngest id (optional), ChEMBL ID chembl_id_col / --chembl-idcol
SMILESPrep id (optional), <smiles_col> (any name) smiles_col / --smiles-col

PubChemIngest accepts PubChem_CID (canonical), PubChem CID, PubChemCID, and CID as input aliases, and always emits PubChem_CID in the output.

Supported file formats: CSV, TSV, TXT, XLSX, XLSM, XLS. .csv is read as comma-delimited and .tsv / .txt as tab-delimited, deterministically and without delimiter sniffing.


Roadmap

Released:

  • v0.2.x — RDKit canonicalization contract (SMILES_RDKit), DataFrame-only pipeline returns with save_table as the single write boundary.
  • v0.3.x — RDKit-native lab harmonization layer (SMILES_Harmonized) with auditable per-row status reporting, and deterministic alias-aware PubChem CID handling emitting a canonical PubChem_CID column.

Deliberately out of scope: molecular fingerprint generation and descriptor calculation, which are handled downstream rather than inside HARMONSMILE. HARMONSMILE stops at the harmonized structure table.


Development

Project Structure

HARMONSMILE/
|-- harmonsmile/
|   |-- __init__.py        # Public API
|   |-- __main__.py        # python -m harmonsmile entry point
|   |-- _cli.py            # CLI implementation
|   |-- chembl.py          # ChEMBL REST client
|   |-- config.py          # PubChemConfig, ChEMBLConfig, SMILESConfig dataclasses
|   |-- io.py              # Table I/O utilities (load_table, save_table)
|   |-- pipelines.py       # PubChemIngest, ChEMBLIngest, SMILESPrep
|   |-- pubchem.py         # PubChem REST client
|   |-- standardize.py     # RDKitStandardizer, HarmonizationResult
|   `-- version.py         # Package version metadata
|-- tests/                 # Unit test suite (pytest) - 187 tests
|-- examples/              # Example datasets and fetch scripts
|-- docs/                  # MkDocs sources (index, usage, api, changelog)
|-- pyproject.toml
|-- mkdocs.yml
|-- requirements-dev.txt
|-- CHANGELOG.md
|-- CITATION.cff
|-- CODE_OF_CONDUCT.md
|-- CONTRIBUTING.md
|-- COPYING
|-- COPYING.LESSER
|-- LICENSE
`-- README.md

Running Tests

python -m pytest tests -p no:cacheprovider --basetemp .pytest_tmp

Contributing

Contributions are welcome. Please open an issue before submitting a pull request. Follow the existing code style: NumPy-style docstrings, type hints, and SPDX license headers in all source files.

See CONTRIBUTING.md for full guidelines, including the development setup and the pull request target branch. Please also read our Code of Conduct.


Citation

If you use HARMONSMILE in your research, please cite it using the metadata in CITATION.cff or the format below:

Contreras-Torres, F. F. (2026). HARMONSMILE: Harmonize SMILES Strings for
Cheminformatics and Machine Learning. Zenodo. https://doi.org/10.5281/zenodo.20275498

Author

Developed by Flavio F. Contreras-Torres (Tecnologico de Monterrey) Monterrey, Mexico


License

This project is licensed under the terms of the GNU Lesser General Public License v3.0 or later. SPDX identifier: LGPL-3.0-or-later.


Statement on AI Assistance

I used conversational AI assistance (Claude, Anthropic) during the development and maintenance of HARMONSMILE. Claude Code was also used to audit the repository against packaging requirements; it reported findings, and I applied the resulting changes myself.

The assistance was primarily conversational and focused on documentation, packaging configuration, dependency management, and incremental refinement. It also covered small, localized code changes such as type annotations, variable naming, and automated import ordering. I engaged with the tool as I would with a technical colleague — asking questions, discussing trade-offs, and iterating on solutions.

The scientific design — including the harmonization policy, column contracts, pipeline boundaries, and reproducibility strategy — is mine. I made the decisions about what the tool should do, how it should behave, and what constitutes a correct result.

I reviewed all changes before integration, ran the test suite, and take full responsibility for the final output. The repository history shows incremental commits, CI runs, and a detailed CHANGELOG, reflecting iterative development rather than generated output.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

harmonsmile-0.3.3.tar.gz (60.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

harmonsmile-0.3.3-py3-none-any.whl (42.2 kB view details)

Uploaded Python 3

File details

Details for the file harmonsmile-0.3.3.tar.gz.

File metadata

  • Download URL: harmonsmile-0.3.3.tar.gz
  • Upload date:
  • Size: 60.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for harmonsmile-0.3.3.tar.gz
Algorithm Hash digest
SHA256 b02693f89cb130dd55472cb6df2afd1e3ef2888e0f0ccfbb5c6193597601fa15
MD5 c47151b44d0cdba5fea2cfd200de2d6a
BLAKE2b-256 8e03c8bbfcf97baf82148f68ab0a2fd53f1b79d3c4fb372251e4af0a205442c6

See more details on using hashes here.

Provenance

The following attestation bundles were made for harmonsmile-0.3.3.tar.gz:

Publisher: publish-to-pypi.yml on NanoBiostructuresRG/harmonsmile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file harmonsmile-0.3.3-py3-none-any.whl.

File metadata

  • Download URL: harmonsmile-0.3.3-py3-none-any.whl
  • Upload date:
  • Size: 42.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for harmonsmile-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 20caf7d1aabaf290de3cd94ec7259c7439feb5e90d506b452b781c3c5745c9cb
MD5 60660404928e95240add42e77472d769
BLAKE2b-256 449c717dab5e381d1dcee4553b4cf6efdc69aa3aee279b9a4b2fe6aae307f6d6

See more details on using hashes here.

Provenance

The following attestation bundles were made for harmonsmile-0.3.3-py3-none-any.whl:

Publisher: publish-to-pypi.yml on NanoBiostructuresRG/harmonsmile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.3 This release

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page