orthonym.assembly.composition_primitives#

Note

Internal API. Names and behaviour may change between releases.

a phase (-03 / internal notes) — shared name-composition primitives.

Single source of truth for the IUPAC / / string-composition grammar, called by BOTH the legacy fragment assembler (handlers/_handler_shared.py:_assemble_fragments) and the Name-Tree serializer (name_tree_to_string._assemble_explicit_fields). There is ONE implementation of each rule — not two — so the legacy path and the production flip path cannot drift (; the no-band-aid mandate in internal notes).

The five core helpers (_estimate_parent_size_from_name, _build_unsaturation_infix, _build_hydrocarbon_name, _join_prefixes, _join_prefix_to_name) were LIFTED VERBATIM from composer.py (a phase) — their bodies are unchanged so the legacy carrier stays byte-identical. composer.py re-exports them under their original names for back-compat.

Leaf-module invariant (Pitfall 4): this module imports ONLY from naming_utils and rules.locant_validation (both confirmed leaves) plus the data.chain_names table — it MUST NOT import composer or NameFragment, so the serializer can import it at module load without an assembly -> composer -> assembly cycle.

orthonym.assembly.composition_primitives.prefix_locant_order_key(locant)#

Order one locant within a multiplied prefix’s locant set.

(the Blue Book): “Italic capital and lower-case letter locants

are lower than Greek letter locants, which, in turn, are lower than numerals”; :3193: “Primed locants are placed immediately after the corresponding unprimed locants in a set arranged in ascending order; locants consisting of a number and a lower-case letter… are placed immediately after the corresponding numeric locant”. So the italic element locants N, N', N2, O, S lead (in their own order: letter, then prime or superscript), then the numerals by value, a letter-suffixed numeral (3a) and a primed one (4') right after their numeral. The Blue Book’s mixed sets: ‘N,*N*,2-trimethyl…propanamide (PIN)’ (:21624), ‘N,1,4-triphenyl-1*H*- 1,2,4-triazol-4-ium-3-aminide (PIN)’ (:42460).

orthonym.assembly.composition_primitives.combine_identical_prefix_groups(entries)#

Merge the prefix groups of one substitutive name that carry the SAME prefix.

entries is an iterable of (name, locants) in citation order, where a name may occur more than once because different producers collected it – the ring or chain carbons in one list, the nitrogens of an amide or amine suffix in another. Returns [(name, locants),...] with every identical name combined into ONE group at its first position, the locants ordered by prefix_locant_order_key().

(the Blue Book) (b) (:7067): the basic multiplying prefixes

“indicate a multiplicity of:… simple substituent prefixes”, and (a) (:7104) ‘bis’, etc., of substituted ones – a multiplicity of the PREFIX, not of the atom kind it sits on. The Blue Book’s PINs cite one group across italic and numeric locants: ‘N,2-dimethylpropanamide’ and ‘N,*N*,2-trimethyl-3- {…}propanamide (PIN)’ (:21624), ‘N,4-dimethyl-N-(3-methylphenyl)benzamide (PIN)’ (:32879), ‘N,1-bis(4-chlorophenyl)methanimine (PIN)’ (:26524), ‘N,1,4-triphenyl-1*H*-1,2,4-triazol-4-ium-3-aminide (PIN)’ (:42460), and across differently numbered nitrogens ‘*N*1,*N*3-dimethylpropanediamide (PIN)’ (:2889). This is the grouping only; each producer keeps its own formatter (marks, multiplier) and its own citation order.

orthonym.assembly.composition_primitives.identical_prefixes_grouped()#

False while:func:identical_prefixes_cited_apart is active: the producers then cite each source’s prefix groups on their own (‘N,N-diphenyl-6-phenyl’) instead of one group per identical prefix (‘N,N,6-triphenyl’).

class orthonym.assembly.composition_primitives.identical_prefixes_cited_apart#

Bases: object

Context: name with identical prefixes of different atoms cited apart.

‘Different isotopic modifications on otherwise identical

substituents’ (the Blue Book): “When two substituent groups are isotopically modified in different ways so that they cannot be combined together using multiplicative terms such as ‘di-’, ‘bis-’, etc., they are cited separately” (:43758). The isotope decorator names the isotope-STRIPPED skeleton, where the groups look identical and are multiplied (‘N,N,6-triphenyl’); when a label sits on one member only, no descriptor can be placed on that name, and the skeleton is named again inside this context so the members stand apart.

orthonym.assembly.composition_primitives.apply_mononuclear_enclosing(prefix_texts, is_mononuclear)#

Apply the mononuclear enclosing rule (the Blue Book).

For a mononuclear parent hydride with >= 2 substituents: the FIRST cited substituent is bare; the SECOND AND FURTHER are EACH enclosed in parentheses (bromo(chloro)(fluoro)methane). Carve-out: when ANY simple prefix carries a multiplicative prefix (dichloro/trifluoro/…) ALL prefixes are left bare/unenclosed — the common-PIN form bromodichlorofluoromethane (the PROTECT case C(Br)(Cl)(Cl)F).

THE single implementation of this rule: _handler_shared._assemble_fragments used to carry a second, near-identical inline copy (differing only in two comment words) and therefore a second copy of the compound-hyphen test; it now calls this function.

orthonym.assembly.composition_primitives.resolve_suffix_prefix_collision(suffix_locants, prefix_pairs, is_ring, parent_size)#

Remove prefix locants that collide with a suffix locant, suffix wins).

Mirrors _assemble_fragments:963-1015. Returns prefix_pairs unchanged when the parent is not a ring, there is no suffix locant, or no collision is detected (the general_acyclic-chain no-op path).

orthonym.assembly.composition_primitives.is_ring_parent_name(parent_text)#

True when the parent stem names a ring system (the collision gate).

Same keyword scan the legacy _assemble_fragments uses inline at _handler_shared.py:966-974 — extracted so the serializer applies the identical ring test.