Skip to main content

MolHarbour

image Ruff codecov

MolHarbour is a unofficial Python wrapper for the Molport REST API. It allows you to search for chemical compounds and retrieve information about them. Additionally, MolHarbour unifies the Molport API variables names and verifies the response data using wonderful Pydantic models.

This library is not affiliated with Molport in any way. Molport is a registered trademark of Molport SIA.

The project was initiated as a part of my master's thesis and and is based on refactored scripts which I wrote to retrive commercial availablity of compounds in chembl database.

Installation

From PyPI

pip install molharbor

From source

pip install git+https://github.com/asiomchen/molharbor

Quickstart

Authentication

To start using MolHarbour, you need to create an instance of the Molport class and log in to the Molport API using your username and password or API key.

from molharbor import Molport

molport = Molport()
molport.login(username="john.spade", password="fasdga34a3")

or API key

molport.login(api_key="16072de6-d318-4324-a82c-08c7dfe64d5d")

Compound search

You can search for compounds using the search method. All the search types are supported( via SearchType enum). Additionally, you can specify the maximum number of results to return using the max_results parameter, and the minimum similarity threshold using the similarity parameter (it is used only for similarity search).

Exact search

from molharbor import SearchType

molport.find("O=C(O)c1ccccc1", search_type=SearchType.EXACT)

[
    [
        MolportCompound(
            smiles="OC(=O)c1ccccc1",
            molport_id="Molport-000-871-563",
            link="https://www.molport.com/shop/compound/Molport-000-871-563",
        ),
        MolportCompound(
            smiles="[2H]c1c([2H])c([2H])c(c([2H])c1[2H])C(O)=O",
            molport_id="Molport-003-927-939",
            link="https://www.molport.com/shop/compound/Molport-003-927-939",
        ),
        MolportCompound(
            smiles="O[13C](=O)c1ccccc1",
            molport_id="Molport-003-929-055",
            link="https://www.molport.com/shop/compound/Molport-003-929-055",
        ),
        MolportCompound(
            smiles="OC(=O)[13c]1[13cH][13cH][13cH][13cH][13cH]1",
            molport_id="Molport-046-688-787",
            link="https://www.molport.com/shop/compound/Molport-046-688-787",
        ),
    ]
]

Similarity search

molport.find("O=C(O)c1ccccc1", search_type=SearchType.SIMILARITY, max_results=5)

[
    [
        MolportCompound(
            smiles="OC(=O)c1ccccc1",
            molport_id="Molport-000-871-563",
            link="https://www.molport.com/shop/compound/Molport-000-871-563",
        ),
        MolportCompound(
            smiles="[2H]c1c([2H])c([2H])c(c([2H])c1[2H])C(O)=O",
            molport_id="Molport-003-927-939",
            link="https://www.molport.com/shop/compound/Molport-003-927-939",
        ),
        MolportCompound(
            smiles="O[13C](=O)c1ccccc1",
            molport_id="Molport-003-929-055",
            link="https://www.molport.com/shop/compound/Molport-003-929-055",
        ),
        MolportCompound(
            smiles="[Zn++].[O-]C(=O)c1ccccc1.[O-]C(=O)c1ccccc1",
            molport_id="Molport-003-986-949",
            link="https://www.molport.com/shop/compound/Molport-003-986-949",
        ),
        MolportCompound(
            smiles="OC(=O)[13c]1[13cH][13cH][13cH][13cH][13cH]1",
            molport_id="Molport-046-688-787",
            link="https://www.molport.com/shop/compound/Molport-046-688-787",
        ),
    ]
]

Superstructure search

molport.find("O=C(O)c1ccccc1", search_type=SearchType.SUPERSTRUCTURE, max_results=5)

[
    [
        MolportCompound(
            smiles="CC=O",
            molport_id="Molport-001-783-184",
            link="https://www.molport.com/shop/compound/Molport-001-783-184",
        ),
        MolportCompound(
            smiles="OCc1ccccc1",
            molport_id="Molport-001-783-216",
            link="https://www.molport.com/shop/compound/Molport-001-783-216",
        ),
        MolportCompound(
            smiles="C=O",
            molport_id="Molport-001-785-627",
            link="https://www.molport.com/shop/compound/Molport-001-785-627",
        ),
        MolportCompound(
            smiles="CCO",
            molport_id="Molport-001-785-844",
            link="https://www.molport.com/shop/compound/Molport-001-785-844",
        ),
        MolportCompound(
            smiles="O",
            molport_id="Molport-003-926-090",
            link="https://www.molport.com/shop/compound/Molport-003-926-090",
        ),
    ]
]

Substructure search

molport.find("O=C(O)c1ccccc1", search_type=SearchType.SUBSTRUCTURE, max_results=5)

[
    [
        MolportCompound(
            smiles="OC(=O)c1ccc2[nH]c(S)nc2c1",
            molport_id="Molport-000-004-519",
            link="https://www.molport.com/shop/compound/Molport-000-004-519",
        ),
        MolportCompound(
            smiles="OC(=O)c1cc(C#N)c(Cl)cc1Cl",
            molport_id="Molport-051-434-827",
            link="https://www.molport.com/shop/compound/Molport-051-434-827",
        ),
        MolportCompound(
            smiles="OC(=O)c1ccc(cc1)-c1ccc(cc1)-c1ccc(cc1)N(c1ccc(cc1)-c1ccc(cc1)-c1ccc(cc1)C(O)=O)c1ccc(cc1)-c1ccc(cc1)-c1ccc(cc1)C(O)=O",
            molport_id="Molport-051-434-831",
            link="https://www.molport.com/shop/compound/Molport-051-434-831",
        ),
        MolportCompound(
            smiles="COC(=O)[C@]1(C[C@H](OC(C)=O)[C@@H](NC(C)=O)[C@@H](O1)[C@H](OC(C)=O)[C@@H](COC(C)=O)OC(C)=O)O[C@H]1[C@@H](OC(=O)c2ccccc2)[C@@H](COC(=O)c2ccccc2)O[C@@H](Oc2ccc(OC)cc2)[C@@H]1OC(=O)c1ccccc1",
            molport_id="Molport-051-434-926",
            link="https://www.molport.com/shop/compound/Molport-051-434-926",
        ),
        MolportCompound(
            smiles="[Na+].[Na+].OC(=O)CN(CC([O-])=O)Cc1cc2c(Oc3cc(O)c(CN(CC(O)=O)CC([O-])=O)cc3C22OC(=O)c3ccccc23)cc1O",
            molport_id="Molport-051-435-130",
            link="https://www.molport.com/shop/compound/Molport-051-435-130",
        ),
    ]
]

Raw response manipulation

MolHarbour design to simplify commonn tasks so .find() method returns a list of MolportCompound objects (which itself is a dataclass object with smiles, molport_id and link field).

However, you can access the raw response using the return_response parameter. Returned Response object inherits from Pydantic BaseModel and contains all the fields from the Molport API response with type validation provided by Pydantic. All the fields have the same name as in Molport API docs, only lowercase and the spaces are replaced with underscores( e.g. Shipment Type -> shipment_type)

from molharbor import SearchType

molport.find(
    "O=C(O)c1ccccc1",
    search_type=SearchType.SUBSTRUCTURE,
    max_results=1,
    return_response=False,
)

[
    [
        MolportCompound(
            smiles="OC(=O)c1cc(C#N)c(Cl)cc1Cl",
            molport_id="Molport-051-434-827",
            link="https://www.molport.com/shop/compound/Molport-051-434-827",
        )
    ]
]

vs

molport.find("O=C(O)c1ccccc1", 
              search_type=SearchType.SUBSTRUCTURE, 
              max_results=1, 
              return_response=True)

[Response(result=Result(status=1, message='Substructure search completed!'), data=Data(molecules=[Molecule(id=45........

Suppliers search

Having a Molport ID, you can search for suppliers using the get_suppliers method. Similar to the find() method, you can receive either a raw Pydantic response or a processed list of SupplierOffer models. Each offer represents one available packing from a supplier catalogue.

offers = molport.get_suppliers("Molport-001-794-639")

Or you could use id values of MolportCompound objects returned by find() method

result = molport.find("C[C@H](CS)C(=O)N1CCC[C@H]1C(O)=O", search_type=SearchType.EXACT, max_results=1)[0]
result

MolportCompound(smiles='C[C@H](CS)C(=O)N1CCC[C@H]1C(O)=O', molport_id='Molport-001-794-639', link=...

offers = molport.get_suppliers(result.molport_id)

Processed supplier offers

The returned models contain the supplier, catalogue, and packing fields from the MolPort response with Pydantic validation.

first_offer = offers[0]
first_offer.supplier_name
first_offer.price
first_offer.model_dump()

Applications that use pandas can construct a dataframe without making it a MolHarbor dependency:

import pandas as pd

df = pd.DataFrame(offer.model_dump() for offer in offers)

Raw response

molport.get_suppliers("Molport-000-871-563", return_response=True)

ResponseSupplier(result=Result(status=1, message='Molecule found!'), data=DataSupplier(molecule=Molecule2(id=871563, molport_id='Molport-000-871-563', smiles='OC(=O)c1ccccc1', .....

Contributing

Contributions are welcome!

We use uv for dependency management. To install the dependencies for development, run:

uv sync

Please make sure to update tests as appropriate. We use ruff for code formatting and linting. Please make sure to run it before opening a pull request.

Additionally, pre-commit hooks are set up to run ruff before each commit. To install them, run:

pre-commit install

Thank you for your contributions!

Metadata

Release files for molharbor 0.1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for molharbor 0.1.6
File Size Uploaded
molharbor-0.1.6.tar.gz 82.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for molharbor 0.1.6
File Interpreter ABI Platform
molharbor-0.1.6-py3-none-any.whl Python 3 none any Details

Total release size: 96.5 kB

Release files / molharbor-0.1.6.tar.gz

Download URL molharbor-0.1.6.tar.gz
Size 82.5 kB
Tags Source
SHA-256 checksum
How to use checksums
0f5aacf52f71f5a41239b24235aad8139d5859f8a9a1181ee51d5290f91efbc0
BLAKE2b-256 checksum
How to use checksums
94d2af48160dec381b41f311492162eb91f07080ce2bbc05a3695c3ec74f0bb9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Release files / molharbor-0.1.6-py3-none-any.whl

Download URL molharbor-0.1.6-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1992cd122fab7a6d7f00dbde0998cf95e5f2c39233e1f36093f1b841412b9079
BLAKE2b-256 checksum
How to use checksums
74d272389147a9895ed16bb8d2dd090ce18100c9eaabf82724395e1db101b1a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.6 This release

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release 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