Python documentationView source ↗
On this page

Batch Workflows

MoleculeBatch is an ordered collection for processing many molecules with a single API call. Valid records keep their original input order through transform, export, and filtering steps.

import cosmolkit as ck

batch = ck.mols_from_smiles_list(
    ["CCO", "c1ccccc1", "not-smiles"],
    errors=ck.BatchErrorMode.KEEP,
).with_parallel_jobs(8)

prepared = batch.with_hydrogens().with_2d_coordinates()

print(prepared.valid_mask())
print(prepared.errors())

repr() on BatchParams, BatchQueryParams, BatchExportParams and BatchImageParams displays every registered configuration field and its current value, including nested configuration. Printing does not execute a progress callback or modify the configuration.

Error Handling

Batch APIs accept errors:

  • "raise" raises an exception when a record fails.

  • "keep" keeps failed records and exposes structured errors. Export methods write valid records and include both existing input errors and new export errors in the returned report. total() == success() + failed() and failed() == len(errors()); there is no separate skipped state.

Omitting errors (or passing None) inherits the batch policy for transforms and exports. New batches default to "raise". An explicit override becomes the returned batch’s policy without modifying the source batch; error_mode() reports that policy. Slices and filtering preserve it. Default BatchParams and BatchExportParams therefore display errors=None (inherit). List-returning queries return None for existing failed records, but still raise on new calculation errors rather than losing their error details.

String modes remain supported, but Python callers can also pass BatchErrorMode enum members. Per-record BatchError values expose the input index, operation name, and message:

for error in batch.errors():
    print(error.index(), error.operation(), error.message())

try:
    ck.mols_from_smiles_list(["C1CC"], errors=ck.BatchErrorMode.RAISE)
except ck.BatchValidationError as exc:
    print(exc.error_count)

The read-only BATCH_ERROR_MODE_MAP converts external string names to enum members when needed.

Batch Values

MoleculeBatch behaves like an ordered Python container. Valid records are returned as Molecule objects and invalid kept records are returned as None:

molecules = prepared.to_list()
first = prepared[0]
tail = prepared[5:]
valid = prepared[prepared.valid_mask()]

for molecule in prepared:
    if molecule is not None:
        print(molecule.to_smiles())

Integer indexing returns Molecule | None because kept invalid records are represented as None. Slices, integer index lists, and boolean masks return a new MoleculeBatch and preserve both input order and the batch-level parallel-job setting.

Export Images

report = prepared.write_images(
    "molecule_images",
    format="png",
    width=300,
    height=300,
    errors="keep",
    filenames=["ethanol.png", "benzene.png", "invalid.png"],
    report_path="image_errors.json",
)

print(report.total(), report.success(), report.failed())

filenames is optional. Entries must match the batch length; None uses the default zero-padded name for that record. Names are relative to the output directory, and missing extensions are filled from format.

Export SDF

SDF input/output paths, output directories and report paths accept str or os.PathLike[str], including pathlib.Path. This also applies to SdfDataset.open(), SdfReader.open() and their configured forms. Byte paths are rejected; custom path objects must return text from __fspath__(). Parameter-object and keyword-based calls use the same rules.

report = prepared.write_sdf(
    "prepared.sdf",
    format="v2000",
    errors="keep",
    report_path="sdf_errors.csv",
)

Use write_sdf_files() when each valid record should be written to its own SDF file:

report = prepared.write_sdf_files(
    "prepared_records",
    format="v2000",
    errors="keep",
    filenames=["ethanol", "benzene.sdf", "invalid.sdf"],
)

Derived Outputs

smiles = prepared.to_smiles_list()
rooted = prepared.to_smiles_list(rooted_at_atom=0)
explicit = prepared.to_smiles_list(
    all_bonds_explicit=True,
    all_hydrogens_explicit=True,
)
svgs = prepared.to_svg_list(width=300, height=300)
bounds = prepared.dg_bounds_matrix_list()
fingerprints = prepared.fingerprint_morgan_list(fp_size=2048)
patterns = prepared.fingerprint_pattern_list(n_bits=2048, tautomeric=False)
atom_pairs = prepared.fingerprint_atom_pair_list(fp_size=2048)

Morgan, Pattern, and AtomPair batch APIs use the same source-backed cores as the single-molecule APIs, preserve record order, and are covered by exact pinned-RDKit parity tests. Pattern batch calls reuse the fixed compile-once SMARTS table and return one result per input; they are not the separate RDKit MolBundle intersection operation. Topological Torsion exposes the same ordered bulk execution through its generator methods. Morgan and AtomPair can also collect provenance through the following MoleculeBatch conveniences:

results = prepared.fingerprint_morgan_with_output_list(
    generator=ck.MorganParams(radius=2, fp_size=2048),
)

for result in results:
    if result is not None:
        print(result.fingerprint().on_bits())
        print(result.additional_output().bit_info_map())

atom_pair_results = prepared.fingerprint_atom_pair_with_output_list(
    generator=ck.AtomPairParams(fp_size=2048),
)

for result in atom_pair_results:
    if result is not None:
        print(result.fingerprint().on_bits())
        print(result.additional_output().bit_info_map())

SMILES Options

to_smiles_list() accepts the same output-shaping options for every record:

  • isomeric_smiles includes stereochemical and isotopic information.

  • canonical returns canonical SMILES when enabled.

  • kekule writes aromatic systems in Kekule form.

  • clean_stereo normalizes stereo output where possible.

  • all_bonds_explicit writes explicit bond symbols.

  • all_hydrogens_explicit writes explicit hydrogens.

  • include_dative_bonds includes dative bond notation.

  • ignore_atom_map_numbers omits atom map numbers from canonical decisions.

  • rooted_at_atom starts traversal from a selected atom index.

Batch Chirality

Batch SMILES output preserves isomeric chirality by default:

chiral_batch = ck.mols_from_smiles_list(
    ["F[C@H](Cl)Br", "F[C@@H](Cl)Br"],
    errors="raise",
)

print(chiral_batch.to_smiles_list(isomeric_smiles=True))
print(chiral_batch.to_smiles_list(isomeric_smiles=False))

Use canonical=False when you want output to stay closer to each record’s input traversal while keeping the same CW/CCW chiral tag path:

print(chiral_batch.to_smiles_list(canonical=False))

Parallel Work

Batch calls use one worker by default; n_jobs=1 can be omitted. Explicit n_jobs or a stored with_parallel_jobs() setting enables more workers. Changing the worker count never changes fingerprint parameters or results.

with_parallel_jobs() returns a new batch with a default worker count for later parallel operations. Because molecule values use copy-on-write storage, this configuration step does not duplicate the molecular data.

configured = batch.with_parallel_jobs(8)
prepared = configured.with_2d_coordinates(errors="keep")
smiles = prepared.to_smiles_list()

Method-level n_jobs still overrides the batch default for a single call:

svgs = prepared.to_svg_list(300, 300, n_jobs=2)

with_progress_bar() returns a new batch with a default Rust-side progress bar setting. Progress is emitted by Rust to stderr, matching the usual terminal stream for progress indicators, and method-level progress_bar overrides the batch default for one call:

tracked = batch.with_parallel_jobs(8).with_progress_bar(True)
prepared = tracked.with_2d_coordinates(errors="keep")
smiles = prepared.to_smiles_list(progress_bar=False)

Pass None to clear the batch-level default and let rayon choose:

default_scheduled = prepared.with_parallel_jobs(None)
quiet = prepared.with_progress_bar(None)