orthonym.assembly.handlers._handler_shared#

Note

Internal API. Names and behaviour may change between releases.

a phase shared handler helpers (DECOMP-01 + internal notes).

Substrate commit 02-00: lazy re-export wrappers around the canonical implementations in composer.py. Per internal notes incremental-migration discipline, composer.py STILL OWNS:

  • _name_iso_x_cyanate (composer.py:2204; 27 LOC) — shared between isocyanate (commit 02-04) and isothiocyanate (commit 02-05) handlers.

  • _name_r_group (composer.py:2233; 217 LOC) — shared between urea (commit 02-08), guanidine (commit 02-09), and the general_acyclic catch-all (Plan-03 commit 03-09).

The substrate ships THIS module so handler files can write the forward-looking import path:

from._handler_shared import name_iso_x_cyanate
from._handler_shared import name_r_group

while internally the symbols delegate (via lazy import inside each function body) to composer.py. When Plan-03 commit 03-10 lands, the function BODIES move here verbatim and composer.py’s _name_iso_x_cyanate + _name_r_group definitions delete. The re-export shape ensures handler files do NOT need to change import paths at thinning time — only this delegation layer flips.

Per internal notes catch-all helper convention: shared logic between multiple handlers MUST live in this module (not duplicated across handlers/). The “≥ 2 handler” threshold is per internal notes + internal notes-DECOMP.md in-file-handler-body inventory.

Anti-pattern hygiene: - -02 banned: do NOT group two handlers into one extraction commit

because they share a body. The handlers are separate files; the SHARED helper lives HERE; each handler imports the helper but keeps its own file + own atomic commit.

  • -12 banned: handler logic in shim (must be 1-3-line wrapper). This module’s helpers ARE the multi-line logic; handlers import them.

References: - composer.py:2204-2230 (_name_iso_x_cyanate) — verbatim source. - composer.py:2233-2449 (_name_r_group) — verbatim source. - internal notes § “Common Conventions” + line 458. - 160-internal notes + — catch-all helper convention + migration.

PHASE 160.2 EXTENSION (Plan-02-01; internal notes +): Six NEW public functions lifted verbatim from composer.py per the two-step “helpers-first” extraction:

  • _generate_chain_parent (composer.py:3785-3818, 33 LOC)

  • _generate_ring_parent (composer.py:3821-3893, 72 LOC)

  • _generate_suffix (composer.py:3934-4076, 142 LOC)

  • _generate_prefixes (composer.py:4079-4282, 203 LOC)

  • _generate_stereodescriptors (composer.py:6634-6704, 70 LOC)

  • _assemble_fragments (composer.py:6799-6954, 155 LOC)

Each function body is COPIED VERBATIM from composer.py per a phase mechanical-translation discipline. composer.py keeps thin re-export shims (from.handlers._handler_shared import _generate_chain_parent at module top) so all in-file call sites in _name_oxime_or_hydrazone, _assemble_amide_name, _assemble_amine_name, _assemble_ring_with_ester_prefixes, _assemble_complex_ring_name remain byte-identical per internal notes forbidden-boundary preservation.

Per internal notes honest-fail-on-data: any byte-identical canary regression at commit 02-01 reverts the commit; remediation lands in a follow-up.

Module-level dependencies resolve via LAZY imports inside each function body to avoid the circular dependency _handler_shared.py -> composer.py -> _handler_shared.py that the composer-side shim re-export creates at module-load time. composer.py imports this module at its top; this module deferring composer.py imports to first call breaks the cycle while preserving byte-identical behavior.

orthonym.assembly.handlers._handler_shared.name_iso_x_cyanate(features, fg_key, suffix_word)#

Common implementation for isocyanate and isothiocyanate naming.

Lazy delegate to composer.py:_name_iso_x_cyanate (composer.py:2204). Per internal notes + PATTERNS first-wave guidance, composer.py owns the canonical body at this commit; this wrapper provides the forward-looking import path handlers._handler_shared.name_iso_x_cyanate for handler files that want stable paths now.

SMARTS pattern: [#6][NX2]=[CX2]=[OX1] (isocyanate) or [#6][NX2]=[CX2]=[SX1] (isothiocyanate). Match tuple: (R_carbon, N, C, O/S).

Parameters:
  • features (Any) – MolecularFeatures object.

  • fg_key (str) – Either 'isocyanate' or 'isothiocyanate'.

  • suffix_word (str) – The functional-class suffix word ('isocyanate' / 'isothiocyanate').

Returns:

Functional class name like 'methyl isocyanate', or None.

Return type:

str | None

See also

composer.py:_name_iso_x_cyanate — canonical implementation. composer.py:_name_isocyanate / _name_isothiocyanate — single-line

callers; both move to handlers/{isocyanate,isothiocyanate}.py.

orthonym.assembly.handlers._handler_shared.name_r_group(mol, start_idx, exclude_atoms)#

Name an R group (substituent fragment) starting from start_idx.

Lazy delegate to composer.py:_name_r_group (composer.py:2233). Per internal notes + PATTERNS first-wave guidance.

Parameters:
  • mol (Any) – RDKit Mol object.

  • start_idx (int) – Atom index of the R-group attachment point.

  • exclude_atoms (set) – Set of atom indices to exclude from the R-group walk (e.g., the functional group atoms already named).

Returns:

Substituent name as IUPAC substituent prefix (e.g., 'methyl', 'phenyl', '4-chlorophenyl'), or None on failure.

Return type:

str | None

See also

composer.py:_name_r_group — canonical implementation; consumed by

urea, guanidine, isocyanate, isothiocyanate, and the general_acyclic catch-all.

orthonym.assembly.handlers._handler_shared.cached_is_complex_ring_system(features)#

: per-features memoization of composer._is_complex_ring_system.

The SMARTS-based complex-ring check is heavy; predicates that call it inside the dispatch loop violate the spirit of internal notes (predicates are pure read-only over already-perceived state). Cache the result on the features object as a private attribute so partial_sat / polycyclic / ring_ester predicates share a single SMARTS evaluation per features instance instead of running it three times per dispatch.

The cache is per-features-instance state owned by features itself; the predicate remains pure with respect to shared/global state.

Parameters:

features (Any) – MolecularFeatures-like object with a mol attribute.

Returns:

True iff the molecule is a complex ring system per the SMARTS check.

Return type:

bool