HARMONSMILE: Harmonize SMILES Strings for Cheminformatics and Machine Learning
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_CIDoutput column for downstream interoperability. - RDKit canonicalization: Generates
SMILES_RDKitas a canonical/isomeric/Kekulé RDKit representation, preserving compatibility with workflows that use Kekulized SMILES for deduplication or comparison. - SMILES harmonization: Generates
SMILES_Harmonizedas a canonical/isomeric/aromatic representation after controlled RDKit-native standardization and harmonization. - Auditable status reporting: Reports harmonization outcomes through
SMILES_Harmonization_StatusandSMILES_Harmonization_Message, distinguishing successful harmonization, controlled transformations, unsupported ambiguous structures, and failures. - Cross-source comparison: Preserves structural bridge fields such as
InChIandInChIKeyto 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 byRDKitStandardizer.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 byRDKitStandardizer.to_lab_harmonized(SMILES). It uses an RDKit-nativeMolStandardizepolicy 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, orfailed.SMILES_Harmonization_Message: short auditable message for warnings, unsupported structures, or failures; empty/None for successfulokrows.
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 harmonsmileTo use your own data instead, point
input_pathat 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.pyandexamples/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 withsave_tableas 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 canonicalPubChem_CIDcolumn.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b02693f89cb130dd55472cb6df2afd1e3ef2888e0f0ccfbb5c6193597601fa15
|
|
| MD5 |
c47151b44d0cdba5fea2cfd200de2d6a
|
|
| BLAKE2b-256 |
8e03c8bbfcf97baf82148f68ab0a2fd53f1b79d3c4fb372251e4af0a205442c6
|
Provenance
The following attestation bundles were made for harmonsmile-0.3.3.tar.gz:
Publisher:
publish-to-pypi.yml on NanoBiostructuresRG/harmonsmile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
harmonsmile-0.3.3.tar.gz -
Subject digest:
b02693f89cb130dd55472cb6df2afd1e3ef2888e0f0ccfbb5c6193597601fa15 - Sigstore transparency entry: 2480302119
- Sigstore integration time:
-
Permalink:
NanoBiostructuresRG/harmonsmile@6397cf15a8f9a3d8ce913caa7d2053d633b86630 -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/NanoBiostructuresRG
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@6397cf15a8f9a3d8ce913caa7d2053d633b86630 -
Trigger Event:
workflow_dispatch
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
20caf7d1aabaf290de3cd94ec7259c7439feb5e90d506b452b781c3c5745c9cb
|
|
| MD5 |
60660404928e95240add42e77472d769
|
|
| BLAKE2b-256 |
449c717dab5e381d1dcee4553b4cf6efdc69aa3aee279b9a4b2fe6aae307f6d6
|
Provenance
The following attestation bundles were made for harmonsmile-0.3.3-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on NanoBiostructuresRG/harmonsmile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
harmonsmile-0.3.3-py3-none-any.whl -
Subject digest:
20caf7d1aabaf290de3cd94ec7259c7439feb5e90d506b452b781c3c5745c9cb - Sigstore transparency entry: 2480302211
- Sigstore integration time:
-
Permalink:
NanoBiostructuresRG/harmonsmile@6397cf15a8f9a3d8ce913caa7d2053d633b86630 -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/NanoBiostructuresRG
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@6397cf15a8f9a3d8ce913caa7d2053d633b86630 -
Trigger Event:
workflow_dispatch
-
Statement type: