Commit Graph

5744 Commits

Author SHA1 Message Date
github-actions[bot]
fd2ea88fdb [bot] Update molecular templates header (#9193) 2026-03-21 09:09:40 +01:00
Andrew Dirksen
cbedbb7819 Hide data representation inside RDKit::Dict (#9113)
* Remove Dict::getData() for a strict abstraction boundary

Replace direct access to Dict's internal std::vector<Pair> with
encapsulated methods: size(), empty(), const iteration via
begin()/end(), appendPair(), markNonPOD(), and getRawVal().

This enables future changes to Dict's internal representation
without breaking callers.

Ref: rdkit/rdkit#9112

* Harden Dict::appendPair to take a populated Pair by move

appendPair(Pair&&) now auto-detects non-POD status via
RDValue::needsCleanup(), eliminating markNonPOD() and the
risk of dangling references or uninitialized entries.

needsCleanup() is placed next to destroy() on RDValue to
keep the POD/non-POD distinction in one place.

* Remove vestigial dictHasNonPOD param from streamReadProp

Both callers ignored the output. Non-POD detection is now handled
by Dict::appendPair via RDValue::needsCleanup().

* unbork java build

* Address PR review: bulk append, rename getRawVal, add custom data test

- Add Dict::append(vector<Pair>&&) for bulk insertion with reserve
- Use bulk append in streamReadProps to restore pre-allocation
- Rename getRawVal -> getRDValue per reviewer preference
- Add test verifying custom AnyTag data is destroyed through Dict lifecycle

* heed self-review

* don't manually implement vec.insert

* Add test: ExplicitBitVect round-trip through Dict serialization

Exercises the full streamWriteProps/streamReadProps path with an
ExplicitBitVect in an RDProps Dict, confirming the custom handler
is invoked and no memory is leaked (verified under valgrind).

* in anyTag test, assert destructors ran a specific number of times.

---------

Co-authored-by: bddap (Coding Agent) <andrew+bot@dirksen.com>
2026-03-20 06:58:36 +01:00
Katharina Buchthal
f7a3f044ff Adjust lower bounds to allow intramolecular H-Bonds (#9188)
* added test case

* implemented lower bounds of potential h-bonds

* suggested changes

---------

Co-authored-by: Katharina Buchthal <katharina.buchthal@phys.chem.ethz.ch>
Co-authored-by: greg landrum <greg.landrum@gmail.com>
2026-03-20 04:36:28 +01:00
Ricardo Rodriguez
680520e0ad Follow up to PR #8968 (#9168)
* implement consistency check

* add more consistency checks

* check direction consistency accross double bond

* clean up directions for non-stereo bonds

* fix counts for second from atom dirs; add check

* handle inconconsistent bond dirs

* add more tests, pubchem cases, and update existing

* drop statics

* fix typo

* make sourceBond arg const

* fix consistency check
2026-03-20 04:28:17 +01:00
Katharina Buchthal
c5de9f8843 Fix issue 9165 & 9166 (#9184)
* added *S-S* and bounds overwriting tests

* fixed *S-S*

* added bounds overwriting test

* searching for the bug

* added test case

* improved tests + fixed bug 9166

* updated ref mols

* regenerated refs

* clean up

* changed ref data

* removed print statements

* Update Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.cpp

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* Typo

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* Incooperated suggestions

* applied remaining suggestions

* restored imports

---------

Co-authored-by: Katharina Buchthal <katharina.buchthal@phys.chem.ethz.ch>
Co-authored-by: Greg Landrum <greg.landrum@gmail.com>
2026-03-19 16:47:04 +01:00
David Cosgrove
88ff241407 Support double* in Transform3D::TransformPoint (#9176)
* Accept non-kekulisable molecules.

* Add Transform3D::TransformPoint(double *)

* Reformat.

---------

Co-authored-by: David Cosgrove <david@cozchemix.co.uk>
2026-03-19 09:34:22 +01:00
Yakov Pechersky
0986d22c58 Deterministic kekulize, independent of atom and bond order (#9125)
* Make kekulization deterministic

* Add tautomer order-independence regression (python)

* Adjust tautomer tests for deterministic kekulization

* Update graphmol wedged-bond kekulization checks

* SmilesParse: update aromatic bond index expectations

* SmilesParse: refresh cxsmilesTest expected files

* Depictor: update testDepictor expected MolBlocks

* Depictor: update depictorCatch expectations

* Depictor Wrap: update expected MolBlock for pyDepictor

* MarvinParse: update testMrvToMol expected outputs

* FileParsers: refresh testAtropisomers expected outputs

* FileParsers: update tests for deterministic kekulization

* MolDraw2D: refresh brittle bond assertions

* RascalMCES: update expected cluster size

* MinimalLib: make cffi wedging check order-independent

* documentation fix

* MinimalLib: update Kekulé bond table in aligned-coords test

* Hoist duplicated lambdas to TEST_CASE scope

* Remove unused originalWedges variable

* Remove redundant bounds check; clarify wedge-end preference

* Pre-sort allAtms by wedge-end + rank

* Use mol.atomNeighbors() for neighbor iteration

* Check inAllAtms before linear-scanning done

* Drop redundant optsV/wedgedOptsV sorts

* Remove unused Canon.h include

* Add canonical parameter to Kekulize; skip ranking during sanitization

* Test canonical re-kekulization preserves stereo across atom orderings

* MinimalLib: update Kekulé bond orders in invertedWedges

* Change Kekulize canonical default to false, expose in Python wrappers

* keep rank order, push_back

* Revert "RascalMCES: update expected cluster size"

This reverts commit a81bb39495.

* docstring change

* expose new flag to python wrapper

* document changes in ReleaseNotes.md

* revert minimallib test changes again

* canonical = true defaults

* Revert "revert minimallib test changes again"

This reverts commit 039e1d84da.

* Reapply "RascalMCES: update expected cluster size"

This reverts commit 7b83a7a3e8.

---------

Co-authored-by: greg landrum <greg.landrum@gmail.com>
2026-03-19 08:43:13 +01:00
Nic Zonta
67b4555611 Switch to using SMARTS for 2D depiction templates (#9179)
* parse templates as smarts

* accept ring templates in SMARTS format

* undo CLAUDE mistake

* rename files
2026-03-19 06:54:23 +01:00
Greg Landrum
972b31e239 Add 'k' extension to SMARTS to support ringsize queries (#9172)
* switch the Query infrastructure to use std::function

* add releasenotes mention

* refactor makeAtomInRingOfSizeQuery() to use lambdas and support range queries

* add 'k' atom query to SMARTS

* changes in response to review
2026-03-17 15:02:59 +01:00
Yakov Pechersky
1a3cc2d5e8 fix: kekulization failure for V3000 molblocks with aromatic bonds and explicit H (#9141)
V3000 parsing sets aromatic flags on bonds but not atoms. When removeHs
strips an explicit H from nitrogen in an aromatic ring, molRemoveH
checked heavyAtom->getIsAromatic() to decide whether to increment
numExplicitHs — but that flag was always false for V3000-parsed atoms.

Without the explicit H count, the kekulizer cannot distinguish pyrrole N from pyridine N,
causing
"Can't kekulize mol" errors on valid ChemDraw-exported molblocks.

Fix: use isAromaticAtom(), which checks both atom and bond aromatic
flags
2026-03-14 06:50:01 +01:00
Greg Landrum
fa011fe425 switch the Query infrastructure to use std::function instead of function pointers (#9169)
* switch the Query infrastructure to use std::function

* add releasenotes mention

* response to review

Removed commented-out function pointer declarations for match and data functions.
2026-03-14 05:57:02 +01:00
Chris Von Bargen
c41f7e7167 Add RDLog::CaptureErrorLog for capturing error log messages (#9138)
* Add RDLog::CaptureLog for capturing log messages

Adds an RAII `CaptureLog` class to `namespace RDLog` (alongside the
existing `LogStateSetter`) that redirects an RDKit logger's output to an
internal `std::stringstream` for the duration of its lifetime. On
destruction the original stream destination and enabled state are fully
restored. Nesting is supported: an inner capture shadows the outer one
and each collects its own messages independently.

The default constructor captures `rdErrorLog`; an explicit constructor
accepts any `RDLogger`. Both enable the logger if it was previously
disabled and restore that state on destruction.

Python bindings expose `rdBase.CaptureLog` as a context manager with a
`messages` read-only property, mirroring the existing `rdBase.BlockLogs`
pattern. Messages remain accessible after the `with` block exits.

C++ tests are added to `catch_logs.cpp` (6 Catch2 sections covering
basic capture, empty state, enable/restore, stream restore, explicit
logger, and nested captures). Python tests are added to
`UnitTestLogging.py` (6 unittest cases covering the same scenarios).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* CaptureLog: add per-level properties (error_messages, warning_messages, etc.)

The Python CaptureLog wrapper now captures all four log levels
simultaneously. Per-level properties (error_messages, warning_messages,
info_messages, debug_messages) give access to messages from each logger
independently; the existing messages property returns them all combined.

The C++ RDLog::CaptureLog class is unchanged — it remains a clean
single-logger RAII type. The Python wrapper composes four instances of
it, one per log level.

Suggested by bp-kelley in PR review.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Refactor CaptureLog: add named per-level subclasses

Add CaptureErrorLog, CaptureWarningLog, CaptureInfoLog, and CaptureDebugLog
as named convenience subclasses of CaptureLog, each capturing a specific
logger. Update Python bindings to expose the four named classes directly
(dropping the combined multi-capture approach), and update tests accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Simplify CaptureLog: no argument, captures rdErrorLog only

Remove the RDLogger argument overload, the four named subclasses, and the
PyCaptureLog template in favor of a single no-argument CaptureLog that
mirrors the Schrödinger CaptureRDErrorLog from which it was inspired.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* CaptureLog tests: add dp_dest restoration and LogStateSetter interaction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Rename CaptureLog to CaptureErrorLog

The name CaptureLog was ambiguous; CaptureErrorLog is explicit about which
logger it captures and avoids redundancy within namespace RDLog.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Generalize CaptureErrorLog into CaptureLog with logger parameter

Replace CaptureErrorLog with CaptureLog, which accepts any RDLogger in
its constructor (e.g. rdErrorLog, rdWarningLog). Add CaptureErrorLog as
a convenience subclass that pre-fills rdErrorLog, preserving backward
compatibility for existing callers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 06:09:43 +01:00
Ricardo Rodriguez
5f85fafb75 Fixes #9153 (#9154)
* add tests

* fix issue

* make test pass under both legacy and modern stereo

* remove the tests
2026-03-12 18:29:59 +01:00
Brian Kelley
ecdf55ac2a Fixes a boundary issue when indexing SDF (#9162)
* Fixes an index boundary error in SDMolSupplier

* Add test data

* Run clang-format

* Update Code/GraphMol/FileParsers/testMolSupplier.cpp

Co-authored-by: Ricardo Rodriguez <ricrogz@users.noreply.github.com>

* Update Code/GraphMol/Wrap/rough_test.py

Co-authored-by: Ricardo Rodriguez <ricrogz@users.noreply.github.com>

---------

Co-authored-by: Ricardo Rodriguez <ricrogz@users.noreply.github.com>
2026-03-12 13:58:33 +01:00
Chris Von Bargen
e8f2b98f4c Fix link failure on macOS caused by AGL framework injection in Qt (#9139)
* Fix Qt 6.5.8 link failure on macOS due to removed AGL framework

Qt 6.5.8 injects the AGL (Apple Graphics Layer) framework into the
WrapOpenGL::WrapOpenGL imported target's INTERFACE_LINK_LIBRARIES. AGL
was removed from macOS 14+ SDKs, causing a link error when building
MolDraw2DQt on modern macOS:

  ld: framework not found AGL

This workaround filters AGL out of WrapOpenGL::WrapOpenGL's link
libraries after find_package(Qt6) populates them. The guard conditions
(APPLE and TARGET WrapOpenGL::WrapOpenGL) make it a no-op on other
platforms and Qt versions that do not create that target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Broaden AGL workaround comment to not pin Qt 6.5.8 specifically

The issue may affect other Qt versions, not just 6.5.8.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 06:12:29 +01:00
Ricardo Rodriguez
f6348578b9 More refactoring in Canon.cpp (#9155)
* dir counts -> vector of char

* cycles: unused

* move ringStereoChemAdjusted

* move and change cyclesAvailable type

* fix tcolor duplication

* move nSwaps

* nix directTravList, cycleEndList

* make cyclesAvailable a bitset

* minor stuff

* make bondDirCounts, atomDirCounts int8_t
2026-03-12 05:54:20 +01:00
Greg Landrum
1e1e734708 Fixes #9144 (#9159)
* Fixes #9144
needs more review;

* remove debugging
a bit more fixing

---------

Co-authored-by: = <=>
2026-03-09 09:07:54 +01:00
Ricardo Rodriguez
46a4f59048 Small refactor before PR #8968 follow up (#9135)
* done

* remove unused arg

* restore parenthesis

* more refactoring

* make checks even stricter

* don't use a string_view
2026-03-01 07:24:59 +01:00
Ricardo Rodriguez
5f1bfa1f78 don't increment counts before checking them (#9136) 2026-03-01 07:19:21 +01:00
David Cosgrove
73682f3700 Add explicit operator= and copy c'tors. (#9133)
Co-authored-by: David Cosgrove <david@cozchemix.co.uk>
2026-03-01 07:18:20 +01:00
Greg Landrum
8e76c27784 Fixes #9117 (#9131) 2026-02-27 04:39:41 +01:00
Rachel Walker
ab06671d0d Fix modern stereo performance issue for large structures (#9100) 2026-02-26 16:40:40 +01:00
Ricardo Rodriguez
d5aa90e18f Fix for issue #8965 (#8968)
* add a test

* change stereo bond canonicalization

* update canonicalization watch test with fixed cases

* make canonicalization test stricter (compare CIP codes)

* add reverse symmetry condition

* rewrite double bond canonicalization code

* update tests

* fix multiline comment

* update java tests

* update python test

* nix switchBondDir (unused)

* fix and rename flipBondDir

* refactor comment

* fix shadowed var name, casting

* fix neighbor sorting

* make seen_bonds a vector

* abstract setDirectionFromNeighboringBond

* handle both sides of the bond have directions

* move getNeighboringStereoBond

* check seen_bonds after popping connectedBondsQ

* use references for arguments

* add release note

* add example required by Dan

* add example requested by Dan
2026-02-26 08:58:36 +01:00
Yakov Pechersky
872b054d5c Defer numpy initialization to first use (#9127)
* Defer numpy initialization to first use in rdchem, rdmolops, cDataStructs

`from rdkit import Chem` unconditionally bootstrapped numpy (~120ms) via
import_array()/boost::python::numpy::initialize() in module init functions,
even when no numpy-dependent APIs were called. This is costly in cold-start
environments like AWS Lambda.

Move numpy initialization behind lazy guards (static bool + first-call init)
in rdchem.so, rdmolops.so, and cDataStructs.so. Numpy now loads only when
an API that actually needs it is invoked (GetDistanceMatrix, GetPositions,
SetPositions, GetAdjacencyMatrix, ConvertToNumpyArray, etc.).

Also change Conformer::SetPos to accept python::object instead of
np::ndarray to prevent Boost.Python from requiring numpy type conversion
before the lazy guard runs.

Adds test_lazy_numpy.py with subprocess-based tests verifying:
- `from rdkit import Chem` does not load numpy
- SmilesToMol/MolToSmiles work without numpy
- numpy loads on demand when array APIs are called

* skip inchi tests if not available

* switch to threadsafe once_flag, like elsewhere

* finish ifdef style

* switch to magic static style

* Revert "switch to magic static style"

This reverts commit 7300188db7.
2026-02-23 18:42:42 +01:00
Ricardo Rodriguez
474df5a9a8 Exclude Zero order bonds from FindRingFamilies() and add arguments for includeDativeBonds, includeHydrogenBonds (#9118) 2026-02-20 19:54:13 +01:00
Yakov Pechersky
67b73acba4 when shifting double bonds in tautomerization, set double bond stereo to STEREOANY (#9119)
* when shifting double bonds in tautomerization, set double bond stereo to STEREOANY

fixes #9102

notably, do this only to non-ring bonds
move tests over to assert this
avoid index-based bond lookup in test assertions
since bond indexing can move in tautomers

* inchi unittest check

* fast rings
2026-02-19 19:29:17 +01:00
Lauriane Jacot-Descombes
42035e6d8a Add valence 1 as possible option for sulfur (#9120)
* Add valence 1 as possible option for sulfur

* Add test for DetermineBonds on thiolates
2026-02-19 13:52:05 +01:00
Greg Landrum
e4f199389b swap zlib download to use github (#9123) 2026-02-19 12:12:36 +01:00
Greg Landrum
8fc241495c Fixes #9107 (#9111)
* Fixes #9107

always include std_unique_ptr.i when using modern SWIG

* allow java tests to build without chemdraw support
2026-02-13 14:11:10 -05:00
Paul Pillot
b952b740d3 Cannot build JS bindings with MCS option enabled. (#9110)
* Cannot push_back std::string to boost json array

`boost::json::array.push_back` expects a `value`

* prefer emplace_back to avoid casting

* Ensure every MINIMAL_LIB option is tested in CI

Also remove Chemdraw support from the compilation. This does not change the final size of the output (not exported anyways) but it reduces the compilation time by 1 min (-10% on my local machine)

* Expose MMPA with other options

* Fix MMPA compilation: Implicitly binding raw pointers is illegal

Applying same pattern as in `get_frags_helper`
2026-02-13 14:54:48 +01:00
Ricardo Rodriguez
f65fd0d8e5 Further refactoring in SSSR finding (#9104)
* use queues instead of sets for trimBonds

* skip 2 last atoms: if these were in rings, we'd have already noticed

* refactor duplicate detection in findRingsD2nodes

* make smallestRingsBfs a free function

* move things around

* fix paper reference; fix other comments
2026-02-13 05:58:14 +01:00
Ricardo Rodriguez
1159026a5d Modernize loops and clean up ring finding (#9098) 2026-02-11 06:06:07 +01:00
Jessica Braun
e4401cd1fc Fix SMARTS for the strict definition of rotatable bonds (#9096) 2026-02-09 17:50:12 +01:00
Eisuke Kawashima
e89c9f656a style: apply readability-braces-around-statements (#8136)
Co-authored-by: Eisuke Kawashima <e-kwsm@users.noreply.github.com>
2026-02-09 12:10:50 +01:00
Greg Landrum
3aab2653cd Fixes #9068: raise a ValueError when trying to set properties with empty names (#9085)
* Fixes #9068

* fix a problem with empty labels in s-group parsing

* fix empty column names in smiles suppliers

* add the check to setPODVal()

---------

Co-authored-by: = <=>
2026-02-09 05:58:25 +01:00
Greg Landrum
c1b67f0c03 fix the python docs for CanonicalRankAtomsInFragment (#9087)
some clang-format reformatting of rdmolfiles.cpp also is in here
2026-02-07 05:54:10 +01:00
Ricardo Rodriguez
813cd85ecc The precondition in Bond::getOtherAtomIdx() is redundant (#9092) 2026-02-06 16:09:23 +01:00
Brian Kelley
36f061efb1 Don't silently ignore missing or extra atoms/bonds in copyMolSubset (#9089)
* Don't silent ignore missing atoms (and replace them with atom #0) in copymolsubet

* Fail if explicitly set atoms/bonds are not present

* Add tests

* Simplify optimization (copy whole molecule) add test for no bonds
2026-02-06 06:48:05 +01:00
Ricardo Rodriguez
dfb34ec23c Another canonicalization fix (#9082)
* update canonicalization test

* fix
2026-02-05 17:24:20 +01:00
Rachel Walker
664d3194b3 Move some fields and methods from AtomPDBResidueInfo to base class (#8863)
* fix pickling

* added python wrapping and test

* fix expected pickles

* trigger CI

* Apply suggestions from code review

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* greg suggestion

* remove additional enum values

---------

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>
2026-02-04 12:13:33 +01:00
Greg Landrum
5df8f93e27 Get things working with numpy 2.4 and pandas 3.0 (#9072)
* get BertzCT working with numpy 2.4

* test pass with with Pandas 3.0
(on windows at least)

* update testRanker too

* update nb test

* run win32 CI tests with different pandas versions
also updates boost version

* works with pandas 2.0?

* update linux_build_py311 -> linux_build_py312
test both old and new pandas

can't go higher with the python version yet because the older pandas and numpy are not available.

* doctest fix?

---------

Co-authored-by: = <=>
2026-02-04 12:06:21 +01:00
tadhurst-cdd
0b5172b62d cleanup of stereogroups and wedges for non-chiral sites (#9051)
* cleanup of stereogroups and wedges for non-chiral sites

* fixed testShapeHelpers for Arm64 build

* reorg the tests a bit

* rename and document option

* add to the python wrappers

---------

Co-authored-by: greg landrum <greg.landrum@gmail.com>
2026-01-30 04:20:32 +01:00
Greg Landrum
cda1b1df2f Fixes #8997 (#9060)
I checked isostar to confirm that the degree-three aromatic N in the pyrrole and pyridone are not acceptors
2026-01-29 12:49:21 -05:00
Ricardo Rodriguez
86902488e9 Store CIP-ranked anchors after CIP labeling. (#9056)
* add the _CIPNeighborRanks property

* store CIP-ranked chiral neighbors

* store CIP-ranked SP2 bond and atropisomer anchors

* add a test

* boost headers in test

* add Atom::NOATOM

* add NOATOM test

* amend and clarify implicit H in Tetrahedral

* rename property

* rename property to _CIPNeighborOrder

* deprecate Chirality::StereoInfo::NOATOM
2026-01-29 18:23:44 +01:00
tadhurst-cdd
2ae0a75a25 Handle chiral atoms with 2 hydrogens in SCSR parser (#8939)
* added flag to allow chiral settings on Atoms with 2 hydrogens for SCSR treatment

* added parameter to allow chiral 2Hs on template mols in SCSR parser

* fixed testShapeHelpers for arm64 build

* Remove checking for two Hs in chiral atom in atomChiralTypeFromBondDirPseudo3D

* removal of flag for allow2Hs

* remove setup.bat file
2026-01-29 08:08:14 +01:00
Ricardo Rodriguez
d3d4170e7c CXSMILES: do not add separators for unserializable Substance Groups (#9048)
* do not write extra separators

* add a test

* update tests

* Update Code/GraphMol/SmilesParse/CXSmilesOps.cpp

---------

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>
2026-01-27 12:35:18 +01:00
David Cosgrove
e598f608fe Transform::SetRotationFromQuaternion takes const. (#9063) 2026-01-24 07:18:41 +01:00
Ricardo Rodriguez
d4641c1f58 Fix removing (non)redundant bond dir specs when exporting SMILES (#9066)
* increase counts to avoid removing non-redundant bond dirs

* update tests
2026-01-24 07:15:00 +01:00
Greg Landrum
21225e63b3 Move some more tests over to catch2 (#9058)
* move testSubstructMatch to catch2

* modernization

* modernization

* switch to catch2

* modernize

* convert to catch2

* update

* move to catch

* please be quiet

* move to catch2

* changes in response to review

---------

Co-authored-by: = <=>
2026-01-24 07:03:04 +01:00
Ricardo Rodriguez
163dd42d4c implement hasPrimaryLabel (#9052) 2026-01-19 14:53:03 +01:00