Skip to content

add molify extra#810

Merged
PythonFZ merged 4 commits intomainfrom
molify-extra
Dec 16, 2025
Merged

add molify extra#810
PythonFZ merged 4 commits intomainfrom
molify-extra

Conversation

@PythonFZ
Copy link
Copy Markdown
Member

@PythonFZ PythonFZ commented Dec 16, 2025

Summary by CodeRabbit

  • New Features

    • Added optional molecule building extensions for creating molecules from chemical notation, packing them with configurable density, and controlling execution timing.
  • Documentation

    • Updated code examples with revised import statements.
  • Chores

    • Restructured molify as an optional dependency with dynamic extension loading for improved installation flexibility.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 16, 2025

Warning

Rate limit exceeded

@PythonFZ has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 50 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 24260d5 and 8126f67.

📒 Files selected for processing (2)
  • Dockerfile (2 hunks)
  • src/zndraw/extensions/molecule_building.py (1 hunks)

Walkthrough

The pull request migrates molecule handling from rdkit2ase to molify, making it an optional dependency in pyproject.toml. A new molecule_building extension module is introduced providing SMILES-to-atoms conversion, molecular packing, and timing utilities. Dynamic extension loading is added to register these modules if molify is available.

Changes

Cohort / File(s) Summary
Dependency & Configuration
pyproject.toml
Moved molify from required dependencies to optional dependencies group named "full"
Documentation Update
docs/source/2025/01.rst
Updated import statement from rdkit2ase to molify for smiles2atoms and smiles2conformers
Extension Registration
src/zndraw/extensions/modifiers.py
Added optional dynamic loading block that imports and registers molify-based extension modifiers if available
New Molecule Building Extensions
src/zndraw/extensions/molecule_building.py
Introduced new module with AddFromSMILES (SMILES-to-molecule conversion), MoleculeSpec (Pydantic model for molecule definition), PackBox (multi-molecule packing), Wait (execution pause), and molify_modifiers registry

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • molecule_building.py — Review the new extension classes for correct run() method implementations, Pydantic schema customization, and molify API usage (smiles2atoms, smiles2conformers, pack)
  • modifiers.py — Verify graceful handling of optional import and ensure the modifiers registry update pattern is correct
  • pyproject.toml — Confirm optional dependency group structure and version constraints

Poem

🐰 A molify migration, clean and bright,
Optional dependencies packed just right,
Extensions building molecules with glee,
From SMILES strings to atoms we shall see!
Pack them in boxes, time to wait,
Our extensions now handle fate! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'add molify extra' directly and accurately describes the main change—converting molify from a core dependency to an optional dependency group in the project configuration.

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/zndraw/extensions/molecule_building.py (3)

25-29: Add type hints for vis parameter.

Per coding guidelines, type hints should be used wherever possible. The run method should have the vis parameter typed.

-    def run(self, vis, **kwargs):
+    def run(self, vis: "ZnDraw", **kwargs) -> None:

You'll need to add the TYPE_CHECKING import at the top:

if t.TYPE_CHECKING:
    from zndraw import ZnDraw

55-70: Add type hints and consider adding return type annotation.

Same as AddFromSMILES, the run method should include type hints for consistency.

-    def run(self, vis, **kwargs):
+    def run(self, vis: "ZnDraw", **kwargs) -> None:

73-85: Consider moving Wait to base modifiers.

Wait doesn't use molify - it only uses the standard library time module. Consider placing it in modifiers.py so it's available even without the molify optional dependency.

Also, add type hints:

-    def run(self, vis, **kwargs):
+    def run(self, vis: "ZnDraw", **kwargs) -> None:
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7922b26 and 24260d5.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • docs/source/2025/01.rst (1 hunks)
  • pyproject.toml (1 hunks)
  • src/zndraw/extensions/modifiers.py (1 hunks)
  • src/zndraw/extensions/molecule_building.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: If sensible, implement collections.abc interfaces for classes, such as MutableMapping or MutableSequence
Use numpy style docstrings
Docstrings must be concise and to the point
Use type hints wherever possible. Import typing as t if necessary, but use list[int|float] | None instead of t.Optional[t.List[int|float]]
Imports should always be at the top of the file

Files:

  • src/zndraw/extensions/modifiers.py
  • src/zndraw/extensions/molecule_building.py
🧬 Code graph analysis (1)
src/zndraw/extensions/molecule_building.py (2)
src/zndraw/extensions/abc.py (2)
  • Category (10-13)
  • Extension (16-31)
src/zndraw/zndraw.py (1)
  • progress_tracker (1772-1793)
🪛 Ruff (0.14.8)
src/zndraw/extensions/molecule_building.py

25-25: Unused method argument: kwargs

(ARG002)


55-55: Unused method argument: kwargs

(ARG002)


79-79: Unused method argument: kwargs

(ARG002)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pytest (3.13, ubuntu-latest)
  • GitHub Check: pytest (3.12, ubuntu-latest)
  • GitHub Check: pytest (3.11, ubuntu-latest)
🔇 Additional comments (5)
docs/source/2025/01.rst (1)

11-11: LGTM!

The import path correctly reflects the migration from rdkit2ase to molify. This aligns with the optional dependency setup in pyproject.toml.

pyproject.toml (1)

45-46: LGTM!

The optional dependency group is correctly configured. Using full is a reasonable convention for including all optional features. Users can install with pip install zndraw[full].

src/zndraw/extensions/molecule_building.py (2)

32-42: LGTM!

Good use of Field with json_schema_extra for custom UI type hints. The model is concise and well-documented.


88-92: LGTM!

The registry follows the same pattern as the base modifiers dict. Type annotation is correct.

src/zndraw/extensions/modifiers.py (1)

436-442: LGTM!

The optional import pattern correctly handles the case when molify is not installed. Using try/except ImportError with silent pass is appropriate for optional features - no need to clutter logs when users haven't installed the optional dependency.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR restructures molify as an optional dependency and adds new molecule building extensions. By moving molify to an optional extra (full), users can install ZnDraw without chemistry-specific dependencies, improving installation flexibility.

  • Moved molify from required dependencies to optional [full] extra
  • Added new extensions: AddFromSMILES, PackBox, and Wait for molecule building workflows
  • Updated Dockerfile to include the full extra for production builds

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pyproject.toml Moved molify from dependencies to optional-dependencies under full extra
uv.lock Updated dependency resolution to mark molify as optional with extra == 'full' marker
src/zndraw/extensions/molecule_building.py New file adding molecule building extensions requiring molify
src/zndraw/extensions/modifiers.py Added optional import of molify_modifiers with ImportError handling
docs/source/2025/01.rst Updated import statement from rdkit2ase to molify
Dockerfile Added --extra full flag to uv sync commands to include molify in Docker builds
Comments suppressed due to low confidence (4)

src/zndraw/extensions/molecule_building.py:91

  • The type annotation type[Extension] is inconsistent with the main modifiers dictionary in modifiers.py which uses t.Type[UpdateScene]. Since these modifiers extend Extension (via UpdateScene being a subclass), the type annotation should be dict[str, type[Extension]] or dict[str, t.Type[Extension]] for consistency with the codebase pattern of using t.Type imported from typing.
    src/zndraw/extensions/molecule_building.py:91
  • The new AddFromSMILES, PackBox, and Wait extensions lack test coverage. Given that the repository has comprehensive test coverage for other modifiers (see tests/test_vis_run_modifier.py), these new extensions should also have tests covering their functionality, edge cases, and error handling.
"""Extensions requiring the molify package."""

import molify
from pydantic import BaseModel, Field

from zndraw.extensions.abc import Category, Extension


class AddFromSMILES(Extension):
    """Add a molecule from SMILES notation."""

    category = Category.MODIFIER
    smiles: str = Field(
        ...,
        json_schema_extra={
            "x-custom-type": "smiles",
            "description": "SMILES notation for molecule",
        },
    )

    def run(self, vis, **kwargs):
        atoms = molify.smiles2atoms(self.smiles)
        vis.append(atoms)
        vis.log(f"Added molecule from SMILES: {self.smiles}")
        vis.step = len(vis) - 1


class MoleculeSpec(BaseModel):
    """Specification for a molecule in PackBox."""

    smiles: str = Field(
        ...,
        json_schema_extra={
            "x-custom-type": "smiles",
            "description": "SMILES notation for molecule",
        },
    )
    count: int = Field(..., ge=1, description="Number of molecules")


class PackBox(Extension):
    """Pack molecules into a box at specified density."""

    category = Category.MODIFIER
    molecules: list[MoleculeSpec] = Field(
        default=[],
        json_schema_extra={"x-custom-type": "smiles-pack-array"},
    )
    density: float = Field(1.0, ge=0.0)

    def run(self, vis, **kwargs):
        conformers = [
            molify.smiles2conformers(mol.smiles, numConfs=mol.count)
            for mol in self.molecules
        ]
        box = molify.pack(
            data=conformers,
            counts=[mol.count for mol in self.molecules],
            density=self.density,
        )
        vis.append(box)
        vis.step = len(vis) - 1
        vis.log(
            f"Packed box with {len(self.molecules)} molecule types "
            f"at density {self.density} kg/m³"
        )


molify_modifiers: dict[str, type[Extension]] = {
    AddFromSMILES.__name__: AddFromSMILES,
    PackBox.__name__: PackBox,
}

src/zndraw/extensions/molecule_building.py:91

  • The Wait extension is defined in this file but not included in the molify_modifiers dictionary. If this extension should be available, it needs to be added to the dictionary. If it's intentionally excluded, consider either removing the class definition or adding a comment explaining why it's not exported.
    src/zndraw/extensions/molecule_building.py:77
  • The field name time shadows the imported time module. This creates ambiguity and could lead to confusion or errors. Consider renaming the field to something like wait_time, duration, or seconds to avoid the naming conflict with the module.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +55 to +70
]
box = molify.pack(
data=conformers,
counts=[mol.count for mol in self.molecules],
density=self.density,
)
vis.append(box)
vis.step = len(vis) - 1
vis.log(
f"Packed box with {len(self.molecules)} molecule types "
f"at density {self.density} kg/m³"
)


molify_modifiers: dict[str, type[Extension]] = {
AddFromSMILES.__name__: AddFromSMILES,
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The run method doesn't validate if the molecules list is empty before processing. When molecules is an empty list (the default), this will create empty conformers and counts lists, which may cause unexpected behavior or errors in molify.pack. Consider adding validation to ensure at least one molecule is specified, or handle the empty case explicitly.

Copilot uses AI. Check for mistakes.
from zndraw.extensions.molecule_building import molify_modifiers

modifiers.update(molify_modifiers)
except ImportError:
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except ImportError:
except ImportError:
# Optional extension not available; safe to ignore if molify is not installed.

Copilot uses AI. Check for mistakes.
@PythonFZ PythonFZ merged commit 665d53e into main Dec 16, 2025
6 checks passed
@PythonFZ PythonFZ deleted the molify-extra branch December 16, 2025 18:36
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Dec 16, 2025

Codecov Report

❌ Patch coverage is 63.33333% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.13%. Comparing base (7922b26) to head (8126f67).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/zndraw/extensions/molecule_building.py 64.00% 9 Missing ⚠️
src/zndraw/extensions/modifiers.py 60.00% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #810   +/-   ##
=======================================
  Coverage   78.13%   78.13%           
=======================================
  Files         152      153    +1     
  Lines       18327    18357   +30     
=======================================
+ Hits        14319    14344   +25     
- Misses       4008     4013    +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot mentioned this pull request Dec 21, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Mar 11, 2026
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.

3 participants