Skip to content

frozen RenderedSubstituentName dataclass - #46

Merged
r-fedorov merged 3 commits into
testsfrom
fix-frozen-RenderedSubstituentName-dataclass
Jul 22, 2026
Merged

frozen RenderedSubstituentName dataclass#46
r-fedorov merged 3 commits into
testsfrom
fix-frozen-RenderedSubstituentName-dataclass

Conversation

@r-fedorov

@r-fedorov r-fedorov commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary by Sourcery

Track and propagate optional outer-parenthesis boundary metadata on rendered substituent names using a frozen dataclass wrapper, and tighten naming-tree metadata validation.

Enhancements:

  • Replace the mutable string subclass used for rendered substituent names with an immutable dataclass carrying text and boundary metadata, plus helpers to split or discard that metadata.
  • Thread rendered substituent boundary information through branch/subgraph naming, component/subgraph substituent collection, and prefix assembly so optional outer parentheses are preserved or omitted correctly.
  • Strengthen naming-tree construction by introducing a typed metadata dict and rejecting unknown or invariant-overwriting metadata fields.
  • Generalize naming protocol and formatting helpers to work with rendered substituent name objects while exposing plain text where required.

Tests:

  • Extend analysis tests to cover naming-tree metadata validation and ensure optional outer parentheses on stereochemical substituents are preserved when reused as substituents or prefixes.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5addd32d-8b8e-4081-b2c8-a136c9cc73e3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-frozen-RenderedSubstituentName-dataclass

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR converts RenderedSubstituentName from a string subclass into a frozen dataclass carrying explicit boundary metadata, propagates the new RenderedSubstituentText type through naming/trace APIs, and tightens tree metadata validation and parentheses-handling logic without changing naming semantics.

Sequence diagram for rendered substituent boundary propagation

sequenceDiagram

participant Namer
participant name_subgraph
participant AssemblyParts
participant add_substituent_trace
participant format_substituent_prefixes

Namer->>name_subgraph: name_subgraph(mol,start_idx,exclude_atoms,upstream_atom)
name_subgraph->>AssemblyParts: _assemble_parent_name(mol,parts,numbered_path,finalize_subgraph=true)
AssemblyParts-->>name_subgraph: RenderedSubstituentName
name_subgraph->>name_subgraph: split_rendered_substituent_name(rendered_name)
name_subgraph-->>Namer: RenderedSubstituentText

Namer->>add_substituent_trace: add_substituent_trace(parts,name,locant,...,outer_parentheses_optional=None)
add_substituent_trace->>add_substituent_trace: split_rendered_substituent_name(name)
add_substituent_trace->>AssemblyParts: update SubstituentItem.outer_parentheses_optional

Namer->>format_substituent_prefixes: format_substituent_prefixes(parts,spiro_subs)
format_substituent_prefixes->>format_substituent_prefixes: _omit_optional_outer_parentheses(...,outer_parentheses_optional)
Loading

File-Level Changes

Change Details Files
Introduce a frozen RenderedSubstituentName dataclass and helper utilities, replacing the previous str-subclass design.
  • Define RenderedSubstituentName as a frozen dataclass with text and outer_parentheses_optional fields and a str implementation.
  • Add RenderedSubstituentText union type plus split_rendered_substituent_name and rendered_substituent_text helpers for extracting text and boundary metadata.
  • Extend SubstituentItem with an outer_parentheses_optional field to carry boundary information through assembly.
src/openclatura/assembly_parts.py
Propagate RenderedSubstituentText through naming protocols and branch naming, ensuring boundary metadata is preserved or stripped where appropriate.
  • Update RecursiveSubgraphNamer Protocol overloads to return RenderedSubstituentText instead of plain str and require keyword-only upstream_atom.
  • Adapt name_subgraph to return RenderedSubstituentText, splitting rendered names to plain text only where required for tree assembly.
  • Introduce _branch_name_text in heteroatom_subgraphs and use split_rendered_substituent_name to consume boundary metadata when rendering nested branches.
  • Update functional prefix helpers and heteroaromatic branch naming to use rendered_substituent_text when only plain text is needed.
src/openclatura/naming_protocols.py
src/openclatura/namer.py
src/openclatura/heteroatom_subgraphs.py
src/openclatura/functional_prefixes.py
Ensure substituent boundary metadata is respected in trace construction, component/subgraph collection, and assembly of prefixes and modifiers.
  • Extend add_substituent_trace to accept RenderedSubstituentText, split names to obtain outer_parentheses_optional, and include this flag when deduplicating or creating SubstituentItem instances.
  • Update subgraph and component branch collection functions to split RenderedSubstituentText and store outer_parentheses_optional on SubstituentItem.
  • Thread outer_parentheses_optional through _add_subgraph_substituents and add_component_substituents when reusing stored substituents.
  • Use aggregated outer_parentheses_optional in format_substituent_prefixes and update _omit_optional_outer_parentheses to depend on the explicit flag rather than isinstance checks.
  • Ensure hydrazone principal suffix modifiers capture and propagate outer_parentheses_optional when converting a branch name into a modifier.
src/openclatura/trace_helpers.py
src/openclatura/namer.py
src/openclatura/component_namer.py
src/openclatura/component_modifiers.py
src/openclatura/assembly_prefixes.py
Tighten naming-tree metadata schema and add tests for metadata validation and parentheses semantics.
  • Introduce NamingTreeMetadata TypedDict to define allowed optional metadata fields for naming-tree nodes and a NAMING_TREE_METADATA_FIELDS constant for validation.
  • Update build_naming_tree_node and build_shortcut_tree_node to use NamingTreeMetadata and raise on unknown or invariant-overwriting metadata keys.
  • Adjust tests to drop direct RenderedSubstituentName usage, rely on SubstituentItem.outer_parentheses_optional, and add new tests for metadata validation and reused stereochemical substituents preserving optional outer parentheses.
src/openclatura/trace_helpers.py
src/openclatura/tests/test_analysis.py
Minor API and formatting adjustments to work with the new rendered name model.
  • Change strip_outer_parentheses to accept RenderedSubstituentName and normalize via rendered_substituent_text.
  • Update various call sites to pass upstream_atom as a keyword-only argument consistent with the updated protocol.
  • Remove unused RenderedSubstituentName imports in modules that no longer inspect the type directly.
src/openclatura/formatting.py
src/openclatura/assembly_prefixes.py
src/openclatura/tests/test_analysis.py
src/openclatura/heteroatom_subgraphs.py
src/openclatura/namer.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/openclatura/tests/test_analysis.py" line_range="311-316" />
<code_context>
     assert shortcut["substituents"] == []


+def test_tree_builder_rejects_unknown_or_invariant_metadata_fields():
+    with pytest.raises(ValueError, match="Unknown tree metadata fields"):
+        build_naming_tree_node(kind="component", name="methane", metadata={"unexpected": []})
+
+    with pytest.raises(ValueError, match="cannot replace invariant fields"):
+        build_naming_tree_node(kind="component", name="methane", metadata={"name": "other"})
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a positive test case that valid metadata is accepted and merged without errors.

To fully exercise the new `NamingTreeMetadata` and `NAMING_TREE_METADATA_FIELDS` logic, please also add a test that passes metadata with all supported keys (`name_atom_bindings`, `name_token_spans`, `stereo_features`, `indicated_hydrogens`, `hydro_operations`, `parent_charges`) and verifies `build_naming_tree_node` returns a node containing these keys plus the invariant fields without raising. This will validate the whitelist and merge behavior, not just the rejection paths.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +311 to +316
def test_tree_builder_rejects_unknown_or_invariant_metadata_fields():
with pytest.raises(ValueError, match="Unknown tree metadata fields"):
build_naming_tree_node(kind="component", name="methane", metadata={"unexpected": []})

with pytest.raises(ValueError, match="cannot replace invariant fields"):
build_naming_tree_node(kind="component", name="methane", metadata={"name": "other"})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add a positive test case that valid metadata is accepted and merged without errors.

To fully exercise the new NamingTreeMetadata and NAMING_TREE_METADATA_FIELDS logic, please also add a test that passes metadata with all supported keys (name_atom_bindings, name_token_spans, stereo_features, indicated_hydrogens, hydro_operations, parent_charges) and verifies build_naming_tree_node returns a node containing these keys plus the invariant fields without raising. This will validate the whitelist and merge behavior, not just the rejection paths.

@r-fedorov
r-fedorov merged commit 0239393 into tests Jul 22, 2026
22 checks passed
@r-fedorov
r-fedorov deleted the fix-frozen-RenderedSubstituentName-dataclass branch July 22, 2026 15:25
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