Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 10 additions & 63 deletions .github/workflows/build-wheels.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,24 @@ name: Build and upload to PyPI

on:
workflow_dispatch:
pull_request:
push:
branches:
- main
release:
types:
- published

jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-latest]

steps:
- uses: actions/checkout@v5
with:
submodules: recursive # Critical: fetch packmol submodule

- name: Build wheels
uses: pypa/cibuildwheel@v3.3.0
env:
# Set macOS deployment target dynamically based on runner
CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=15.0

- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl

build_sdist:
name: Build source distribution
pypi-publish:
name: Upload release to PyPI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
submodules: true

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Build SDist
run: uv build --sdist

- name: Upload SDist
uses: actions/upload-artifact@v4
with:
name: cibw-sdist
path: dist/*.tar.gz

upload_pypi:
needs: [build_wheels, build_sdist]
environment:
name: pypi
url: https://pypi.org/p/molify
permissions:
id-token: write
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
steps:
- name: Download all artifacts
uses: actions/download-artifact@v5
with:
pattern: cibw-*
path: dist
merge-multiple: true

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- uses: actions/checkout@v5
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Build
run: |
uv build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

1 change: 0 additions & 1 deletion external/packmol
Submodule packmol deleted from 7cb4c1
116 changes: 0 additions & 116 deletions hatch_build.py

This file was deleted.

9 changes: 2 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "molify"
version = "0.2.0"
version = "0.2.1"
description = "Molecular Structure Interface with RDKit, ASE, Packmol and NetworkX"
readme = "README.md"
license = "Apache-2.0"
Expand All @@ -12,6 +12,7 @@ dependencies = [
"ase>=3.25.0",
"matplotlib>=3.10.1",
"networkx>=3.4.2",
"packmol>=21.1.2",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Critical: Invalid PyPI dependency — packmol is not published on PyPI.

The dependency "packmol>=21.1.2" cannot be resolved. The PACKMOL program is not distributed as a package on PyPI; it is distributed via GitHub releases, conda-forge, or compiled from source. This matches the issue flagged in the previous review. The PR description indicates the checklist item "wait for PyPI release of packmol with correct version number" is still unchecked, confirming the PyPI package is not yet available.

pip install molify will fail when this dependency cannot be resolved.

Please confirm the package availability:

If PACKMOL is not published to PyPI, consider:

  1. Making it optional: Move to [project.optional-dependencies] or [dependency-groups] dev if packmol is only needed for certain features.
  2. Using conda instead: Update installation docs to guide users to conda install -c conda-forge packmol before pip install molify.
  3. Waiting for upstream: Ensure the PACKMOL project actually publishes to PyPI before merging this PR.

🌐 Web query:

Is there a "packmol" package version 21.1.2 available on PyPI?

💡 Result:

Short answer: No — Packmol (including v21.1.2) is not available on PyPI. Packmol is distributed from its source/GitHub and via conda-forge (conda); mbuild and other docs note PACKMOL is not on pip. (github.com)

Citations:


Critical: Remove invalid PyPI dependency — packmol is not published on PyPI.

Packmol (including v21.1.2) is not available on PyPI and is distributed from its source/GitHub and via conda-forge. The dependency "packmol>=21.1.2" cannot be resolved during pip install molify, causing installation to fail. The PR description checklist confirms the PyPI release is still pending (unchecked item: "wait for PyPI release of packmol with correct version number").

Remove this line from pyproject.toml or move packmol to optional dependencies until the package is officially released to PyPI. If packmol is required for certain features only, use [project.optional-dependencies] and update documentation to guide users to install via conda install -c conda-forge packmol first.

🤖 Prompt for AI Agents
In pyproject.toml around line 15, the dependency "packmol>=21.1.2" is invalid
because Packmol is not on PyPI; remove that line or move packmol into
[project.optional-dependencies] (e.g. extras like "packmol") and update project
docs/README to instruct users to install packmol via conda-forge (conda install
-c conda-forge packmol) before using the features that require it; ensure the
packaging metadata no longer references a non-PyPI requirement so pip install
molify succeeds.

"rdkit>=2024",
]

Expand Down Expand Up @@ -57,11 +58,5 @@ extend-ignore = [
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.hooks.custom]
path = "hatch_build.py"

[tool.hatch.build.targets.wheel]
packages = ["src/molify"]

[tool.codespell]
skip = "*.ipynb"
Binary file removed src/molify/binaries/packmol
Binary file not shown.
14 changes: 3 additions & 11 deletions src/molify/pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from ase.io.proteindatabank import write_proteindatabank
from rdkit import Chem

from molify.packmol import get_packmol_binary
from molify.utils import calculate_box_dimensions

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -147,7 +146,7 @@ def pack(
seed: int = 42,
tolerance: float = 2,
verbose: bool = False,
packmol: str | None = None,
packmol: str = "packmol",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Breaking change: Verify documentation and migration guide.

Changing from packmol: str | None = None to packmol: str = "packmol" is a breaking change. Users who previously relied on the bundled Packmol binary will now need to install Packmol separately and ensure it's available in their system PATH.

Run the following script to check if the README or documentation mentions the new Packmol installation requirement:


🏁 Script executed:

#!/bin/bash
# Check if documentation mentions packmol installation requirement

echo "=== Checking README ==="
fd -t f "README" --exec cat {} \; | grep -i "packmol" -C 3

echo -e "\n=== Checking docs directory ==="
fd -t f . docs/ --exec grep -l "packmol" {} \; 2>/dev/null | head -5

echo -e "\n=== Checking for installation instructions ==="
rg -i "install.*packmol|packmol.*install|pip install.*packmol" -C 2

Length of output: 967



🏁 Script executed:

#!/bin/bash
# Check documentation content and changelog

echo "=== README content (full) ==="
fd -t f "README*" --exec cat {} \;

echo -e "\n=== Checking docs/source/index.rst ==="
cat docs/source/index.rst 2>/dev/null | head -100

echo -e "\n=== Looking for CHANGELOG or version notes ==="
fd -t f "CHANGELOG|HISTORY|CHANGES|NEWS" --exec cat {} \; 2>/dev/null | head -50

echo -e "\n=== Checking if pack.py has error messages about packmol ==="
rg -n "packmol" src/molify/pack.py | head -20

Length of output: 6392



🏁 Script executed:

#!/bin/bash
# Check setup configuration and error handling

echo "=== Checking setup.py / pyproject.toml ==="
fd -t f "setup.py|pyproject.toml|setup.cfg" --exec cat {} \;

echo -e "\n=== Error handling in pack.py around line 227-234 ==="
sed -n '220,240p' src/molify/pack.py

echo -e "\n=== Full _run_packmol function ==="
sed -n '63,80p' src/molify/pack.py

Length of output: 2791



🌐 Web query:

What does the packmol package on PyPI provide?

💡 Result:

There isn't an official "packmol" Python library on PyPI that contains the PACKMOL solver itself. PACKMOL is a standalone packing program (source/binaries distributed from the project site and via conda-forge) that creates initial molecular configurations for MD simulations. PyPI instead hosts related packages that wrap or integrate PACKMOL (e.g. packmol-step — a SEAMM plug‑in for building periodic fluid boxes; mdapackmol — an MDAnalysis wrapper around Packmol). [1][2][3]

Sources:

  • PACKMOL official site / project (download, description). [1]
  • packmol-step (PyPI) — SEAMM plug‑in using Packmol. [2]
  • mdapackmol (PyPI) — MDAnalysis wrapper around Packmol. [3]


🌐 Web query:

packmol PyPI package what is it

💡 Result:

Short answer: "Packmol" is primarily a standalone program (written in Fortran) that builds initial molecular configurations by packing molecules into user‑defined regions for molecular‑dynamics or docking setups. It is not primarily a pure‑Python PyPI package — instead you usually install the Packmol executable (e.g., from the Packmol GitHub/releases or via conda‑forge) and use Python wrappers on PyPI that call it (examples: mdapackmol, packmol-step). Sources: Packmol GitHub (project & install info) [1], PyPI pages for Python wrappers (mdapackmol, packmol‑step) [2][3].

References

  • Packmol GitHub (project, build/install instructions). [1]
  • mdapackmol — "An MDAnalysis wrapper around Packmol" (PyPI). [2]
  • packmol-step — SEAMM/Packmol plugin (PyPI). [3]


🌐 Web query:

packmol 0.1.0 PyPI package

💡 Result:

There is no official PyPI package named "packmol" (version 0.1.0) — PACKMOL is distributed from its upstream site and via OS packages; Python wrappers/integration packages exist on PyPI (e.g., packmol-step, mdapackmol). Sources: PACKMOL upstream (download/docs). [1] Packmol-step on PyPI. [2] MDAPackmol on PyPI. [3]

Sources

  • PACKMOL homepage (upstream downloads/docs). [1]
  • packmol-step on PyPI (example PyPI package integrating PACKMOL). [2]
  • mdapackmol on PyPI (MDAnalysis wrapper around PACKMOL). [3]


🏁 Script executed:

#!/bin/bash
# Check if there's actually a packmol package on PyPI or if this is a broken dependency

echo "=== Searching for any reference to packmol package in repo ==="
rg -i "packmol" pyproject.toml setup.py setup.cfg 2>/dev/null

echo -e "\n=== Checking if packmol is imported anywhere ==="
fd -t f "\.py$" --exec grep -l "import packmol\|from packmol" {} \; 2>/dev/null

echo -e "\n=== Looking at imports in pack.py ==="
head -30 src/molify/pack.py

Length of output: 1268



🏁 Script executed:

#!/bin/bash
# Final verification - check git history or comments about packmol dependency

echo "=== Checking git log for packmol changes ==="
git log --oneline -20 2>/dev/null | head -10

echo -e "\n=== Check if this is perhaps a typo or if packmol.py file exists ==="
fd -t f "packmol" src/

echo -e "\n=== Look at molify.packmol module (referenced in pyproject.toml) ==="
fd -t f "packmol.py" --exec head -50 {} \;

Length of output: 649



🏁 Script executed:

#!/bin/bash
# Check the latest commit details

echo "=== Full commit message for latest packmol change ==="
git show df9c6e8 --stat 2>/dev/null

echo -e "\n=== What changed in that commit ==="
git show df9c6e8 --no-stat 2>/dev/null | head -100

echo -e "\n=== Check if packmol package actually exists by searching PyPI ==="
python3 << 'EOF'
import urllib.request
import json
try:
    with urllib.request.urlopen("https://pypi.org/pypi/packmol/json") as response:
        data = json.loads(response.read().decode())
        print(f"Package found: {data['info']['name']}")
        print(f"Latest version: {data['info']['version']}")
        print(f"Description: {data['info']['summary']}")
except urllib.error.HTTPError as e:
    print(f"Package not found on PyPI (HTTP {e.code})")
EOF

Length of output: 2740


Multiple critical issues: Broken dependency, misleading documentation, and unhandled breaking change.

The breaking change itself is legitimate, but the implementation has critical flaws:

  1. Broken PyPI dependency: pyproject.toml lists packmol>=0.1.0, but web search confirms no official PyPI package named "packmol" exists. Installation will fail with "ERROR: Could not find a version that satisfies the requirement packmol>=0.1.0".

  2. Outdated README: README states "The molify package ships with an installation of packmol" — this is now false and will confuse users.

  3. Insufficient error handling: The subprocess call to packmol (line 72 in _run_packmol) will fail silently or with a cryptic error if the executable is missing. No validation before attempting execution.

  4. Missing installation guidance: Users upgrading will face installation failure, then need to manually install packmol externally — but there's no documentation explaining this requirement or how to install the actual PACKMOL binary from the official source.

Remove the broken packmol>=0.1.0 dependency from pyproject.toml, update the README and documentation to clearly state that PACKMOL must be installed separately (e.g., via conda-forge or from the official GitHub), and add validation in the code to provide a helpful error message if the packmol executable is not found.

🤖 Prompt for AI Agents
In src/molify/pack.py around line 149, the constant packmol: str = "packmol" and
related code must guard against missing external PACKMOL binary and inform
docs/package metadata: update code to check for the packmol executable before
invoking subprocess (use shutil.which or pathlib to verify PATH), raise a clear,
user-facing exception with actionable install instructions (e.g., "PACKMOL
executable not found; install via conda-forge or from
https://github.com/wordom/packmol") if not found, and ensure subprocess calls
only run after this validation; separately remove the invalid pyproject
dependency on packmol>=0.1.0 and update README/docs to state PACKMOL is an
external dependency with installation guidance.

pbc: bool = True,
output_format: FORMAT = "pdb",
ratio: tuple[float, float, float] = (1.0, 1.0, 1.0),
Expand All @@ -169,11 +168,8 @@ def pack(
The tolerance for the packing algorithm, by default 2.
verbose : bool, optional
If True, enables logging of the packing process, by default False.
packmol : str or None, optional
The path to the packmol executable. If None (default), uses the bundled
packmol binary shipped with molify. You can provide a custom path to
use a different packmol installation (e.g., "packmol" to use system
PATH, or "/path/to/custom/packmol").
packmol : str, optional
The path to the packmol executable.
pbc : bool, optional
Ensure tolerance across periodic boundaries, by default True.
output_format : str, optional
Expand All @@ -199,10 +195,6 @@ def pack(
>>> print(packed_system)
Atoms(symbols='C10H44O12', pbc=True, cell=[8.4, 8.4, 8.4])
"""
# Use bundled packmol binary if not specified
if packmol is None:
packmol = str(get_packmol_binary())

selected_images = _select_conformers(data, counts, seed)
cell = calculate_box_dimensions(images=selected_images, density=density)

Expand Down
102 changes: 0 additions & 102 deletions src/molify/packmol.py

This file was deleted.

Loading
Loading