Skip to content

Modern Python + rdkit support (build on #40) - #42

Open
pbio wants to merge 4 commits into
MolecularAI:mainfrom
pbio:modern-python
Open

Modern Python + rdkit support (build on #40)#42
pbio wants to merge 4 commits into
MolecularAI:mainfrom
pbio:modern-python

Conversation

@pbio

@pbio pbio commented Sep 1, 2026

Copy link
Copy Markdown

Summary

Extends #40 (Edison's Python 3.13 support work) with three additional commits that address the review feedback from @CKannas and remove rdkit-version-gated test logic in favor of behavior-based checks.

Included in this PR:

  • Edison's commit (2059677) is preserved intact: Python 3.13 support, per-Python-version rdkit/numpy pins, SCScore numpy-2 fix, and the initial atom_properties fix for the GetValence signature change.
  • New commit (8fcf6d6) — Drop rdkit version gates in favor of behavior-based tests: replaces all _NEW_RDKIT conditionals in tests/test_reaction.py and tests/test_template.py. The parametrized template test now compares reaction graphs (atoms + bonds keyed on atom-map number) rather than exact SMARTS strings. The hash tests now assert on invariants (determinism, distinguishing, well-formed SHA224) rather than pinned hex values. The [AlH3] / [#13&H3] equality row was swapped for [CH3] / [#6&H3] since Al was incidental to the notation-equivalence check. The chiral fingerprint test was rewritten to use a genuine [C@H] vs [C@@H] enantiomer pair on a scaffold with four distinguishable substituents, which is chemically well-defined across all rdkit versions.
  • New commit (32eabd7) — Address version-constraint feedback from PR review: applies exactly the four version splits @CKannas requested (rdkit <2024.9.1, numpy >=2.0.0, per-Python scipy split, per-Python onnxruntime split) plus the poetry=2.4.0 pin in env-dev.yml.
  • New commit (14f8467) — Replace GetValence blocklist with TypeError catch in atom_properties: Boost.Python.ArgumentError inherits from TypeError, so catching that in the reflective Get* loop removes the need for a hardcoded blocklist and works forward against any future signature change. Also updates the code comment — GetValence was actually introduced in rdkit 2025.03.1 (not 2024).

Test plan

Verified with the full test suite (pytest --deselect tests/test_rinchi.py; the two rinchi failures are pre-existing on macOS and unrelated) on Python 3.12 against five rdkit versions across four major series:

  • rdkit 2023.9.6 — 289 pass
  • rdkit 2024.3.6 — 289 pass (newly-permitted by the widened <2024.9.1 cap)
  • rdkit 2024.9.3 — 289 pass
  • rdkit 2025.9.6 — 289 pass
  • rdkit 2026.3.5 — 289 pass

Zero failures anywhere. No version-conditional test logic remains in either test file.

Kosmos and others added 4 commits May 8, 2026 22:25
* Bump python upper bound to <3.14 in pyproject.toml and env-dev.yml.
* Use per-Python-version pins for numpy and rdkit so 3.9-3.12 users
  keep numpy<2 / rdkit ^2023.9.1 (no degradation), while 3.13 picks
  up numpy>=2.1 / rdkit>=2024.9.1 (the first versions with cp313
  wheels).
* SCScore._make_fingerprint: use DataStructs.ConvertToNumpyArray
  instead of np.array(bitvect, dtype=float). The latter segfaults
  under rdkit>=2026 + numpy>=2.
* TemplateMolecule.atom_properties: swallow Boost.Python.ArgumentError
  from RDKit getters whose signatures changed in rdkit>=2024
  (e.g. Atom.GetValence now requires a ValenceType arg).
* Mark a handful of template/hash tests xfail on Python 3.13 because
  rdkit>=2024 produces different fingerprint hashes / template SMARTS
  for those inputs.

Tests: 287 pass / 0 fail on Python 3.12 (baseline preserved);
282 pass / 6 xfail / 3 xpass on Python 3.13.
The three tests previously gated on `_NEW_RDKIT` asserted rdkit-specific
implementation details rather than the properties they were meant to
verify. Rework each so a single assertion works on any rdkit version:

* test_template_creation_different_radius: compare template graphs
  (atoms + bonds keyed on atom-map number) rather than the exact SMARTS
  string, which depends on rdkit's writer branch order.
* test_hash_from_smiles / test_hash_from_smarts: check the hash function's
  invariants (deterministic, distinguishing, well-formed SHA224) instead
  of pinning a specific hex value derived from rdkit's canonical writer.
* test_template_equality (Al row): swap the [AlH3] / [MolecularAI#13&H3] pair for
  [CH3] / [MolecularAI#6&H3]. The test's intent is element-symbol vs. atomic-number
  SMARTS notation equivalence; Al was incidental and its valence is now
  rejected by rdkit>=2024's property cache.
* test_template_equality_chiral: replace the ambiguous stereocenter (three
  identical -C substituents, distinguished only by atom-map numbers) with
  a genuine [C@H] vs [C@@h] enantiomer pair on an asymmetric scaffold.
  The old assertion held only because rdkit<2024 treated atom-map numbers
  as chirality-distinguishing.

Full suite passes on rdkit 2023.9.6 and 2024.9.3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apply the four changes CKannas requested in the review of MolecularAI#40:

* rdkit (Python <3.13): loosen upper bound from <2024.0.0 to <2024.9.1
  so the 2024.3.x series is available before Python 3.13 wheels start.
* numpy (Python >=3.13): lower floor from >=2.1.0,<3.0.0 to >=2.0.0
  (rdkit >=2024.9.1 is compatible with NumPy 2.0).
* scipy: split into <3.13 -> >=1.11.4,<1.14.1 and >=3.13 -> >=1.14.1
  since scipy 1.14 dropped Python 3.9 support.
* onnxruntime: split into <3.12 -> <1.17.0 and >=3.12 -> >=1.17.0.

Also pin poetry to 2.4.0 in env-dev.yml per the same review.

Regenerated poetry.lock against the new constraints. Full test suite
passes on rdkit 2023.9.6, 2024.3.6, 2024.9.3, 2025.9.6, and 2026.3.5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The introspection loop in `TemplateMolecule.atom_properties` walks every
`Get*` method on the atom object. A prior fix carried a hardcoded
`_ZERO_ARG_GETTER_BLOCKLIST` to skip `GetValence`, whose signature was
said to change in rdkit>=2024.

That version was wrong: `GetValence` was actually introduced (with a
required `ValenceType` argument) in rdkit 2025.03.1. In earlier releases
it isn't a method on `Atom` at all, so it never appears in `dir(atom)`
and the loop skipped it naturally.

Rather than keep chasing rdkit-version boundaries, catch `TypeError`
around the reflective call. `Boost.Python.ArgumentError` (raised by
rdkit's bindings on argument mismatches) is a `TypeError` subclass, so
this covers `GetValence` and any future signature change with no
per-version code and no imports of Boost.Python internals.

Verified against the full test suite on rdkit 2023.9.6, 2024.3.6,
2024.9.3, 2025.9.6, and 2026.3.5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant