-
Notifications
You must be signed in to change notification settings - Fork 1
improve julia / packmol detection #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Warning Rate limit exceeded@pre-commit-ci[bot] has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 38 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. 📒 Files selected for processing (2)
WalkthroughAdds Julia Packmol version detection via a new utility, integrates version-aware logging into pack(), and improves error handling when Packmol output is missing. Introduces a module logger, a FORMAT type alias, and a unit test asserting a specific Julia Packmol version string. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant pack as pack()
participant utils as get_packmol_julia_version()
participant Julia as julia Pkg.status
participant Packmol as Packmol (CLI/Julia)
participant FS as Filesystem
User->>pack: call pack(output_format)
alt Using Julia Packmol
pack->>utils: get_packmol_julia_version()
utils->>Julia: run `Pkg.status("Packmol")`
Julia-->>utils: stdout (version info)
utils-->>pack: "vX.Y.Z" or error
Note over pack: Logs Packmol Julia version/path
else Non-Julia Packmol
Note over pack: Proceed without version query
end
pack->>Packmol: execute with input script
Packmol-->>FS: write mixture.{format}
pack->>FS: read mixture.{format}
alt Output missing
pack-->>User: raise FileExistsError with logged context
else Output present
pack-->>User: return Atoms
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Pre-merge checks (2 passed, 2 warnings, 1 inconclusive)❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
Poem
✨ Finishing Touches
🧪 Generate unit tests
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. Comment |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #74 +/- ##
==========================================
- Coverage 97.33% 96.52% -0.81%
==========================================
Files 25 25
Lines 1723 1756 +33
==========================================
+ Hits 1677 1695 +18
- Misses 46 61 +15 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
rdkit2ase/utils.py (1)
226-256: Make Julia detection robust: support custom Julia path, handle not-found/timeout, and parse output safely
- Hardcodes "julia" and misses a way to pass a custom interpreter path (PR objective).
- Missing handling for FileNotFoundError/TimeoutExpired; current except only catches CalledProcessError.
- Parsing with split()[2] is brittle across Pkg.status formats; prefer a regex.
- Deduplicate/clarify the repeated long error message; include the interpreter path used.
Apply this diff within the function:
-def get_packmol_julia_version() -> str: +def get_packmol_julia_version(julia: str | None = None, timeout: float = 30.0) -> str: @@ - try: - result = subprocess.run( - ["julia", "-e", 'import Pkg; Pkg.status("Packmol")'], - capture_output=True, - text=True, - check=True, - ) - for line in result.stdout.splitlines(): - if "Packmol" in line: - parts = line.split() - if len(parts) >= 3: - return parts[2] - raise RuntimeError( - "Failed to get Packmol version via Julia. Please verify that you can" - ' import packmol via `julia -e "import Pkg; Pkg.status("Packmol")"`' - ) - - except subprocess.CalledProcessError as e: - raise RuntimeError( - "Failed to get Packmol version via Julia. Please verify that you can" - ' import packmol via `julia -e "import Pkg; Pkg.status("Packmol")"`' - ) from e + import os, re, shutil + cmd = julia or os.environ.get("JULIA", "julia") + resolved = shutil.which(cmd) or cmd # allow absolute/custom paths + try: + result = subprocess.run( + [resolved, "-e", 'import Pkg; Pkg.status("Packmol")'], + capture_output=True, + text=True, + check=True, + timeout=timeout, + ) + except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired) as e: + raise RuntimeError( + f"Failed to get Packmol version via Julia at '{cmd}'. " + "Ensure Julia is installed and Packmol.jl is available. " + "Try: julia -e 'import Pkg; Pkg.status(\"Packmol\")'." + ) from e + for line in result.stdout.splitlines(): + m = re.search(r"\bPackmol\b[^\n]*\b(v?\d+\.\d+\.\d+(?:[+-].+)?)", line) + if m: + ver = m.group(1) + return ver if ver.startswith("v") else f"v{ver}" + raise RuntimeError( + "Could not parse Packmol version from Julia Pkg.status output. " + "Run locally: julia -e 'import Pkg; Pkg.status(\"Packmol\")'." + )If needed outside this hunk, I can add imports/constants to the module.
rdkit2ase/pack.py (2)
63-88: Remove shell=True, pass stdin explicitly, and support custom Julia path
- shell=True with user-provided executables is avoidable; pass argv list + stdin for Packmol.
- Support a custom Julia path by threading it through to get_packmol_julia_version and the run command (PR objective).
Apply this diff:
-def _run_packmol( - packmol_executable: str, - input_file: pathlib.Path, - tmpdir: pathlib.Path, - verbose: bool, -) -> None: +def _run_packmol( + packmol_executable: str, + input_file: pathlib.Path, + tmpdir: pathlib.Path, + verbose: bool, + julia: str | None = None, +) -> None: @@ - if packmol_executable == "packmol.jl": - version = get_packmol_julia_version() + if packmol_executable == "packmol.jl": + version = get_packmol_julia_version(julia=julia) if verbose: print(f"Using Packmol version {version} via Julia") with open(tmpdir / "pack.jl", "w") as f: f.write("using Packmol \n") f.write(f'run_packmol("{input_file.name}") \n') - command = f"julia {tmpdir / 'pack.jl'}" + command = [(julia or "julia"), str(tmpdir / "pack.jl")] else: - command = f"{packmol_executable} < {input_file.name}" + command = [packmol_executable] - subprocess.run( - command, - cwd=tmpdir, - shell=True, - check=True, - capture_output=not verbose, - ) + if packmol_executable == "packmol.jl": + subprocess.run( + command, + cwd=tmpdir, + shell=False, + check=True, + capture_output=not verbose, + ) + else: + with open(input_file, "rb") as fin: + subprocess.run( + command, + cwd=tmpdir, + shell=False, + check=True, + capture_output=not verbose, + stdin=fin, + )
152-162: Expose a julia parameter on pack() and thread it throughAllows callers to pass a custom Julia interpreter path (PR objective).
Apply this diff:
def pack( data: list[list[ase.Atoms]], counts: list[int], density: float, seed: int = 42, tolerance: float = 2, verbose: bool = False, packmol: str = "packmol", pbc: bool = True, - output_format: FORMAT = "pdb", + output_format: FORMAT = "pdb", + julia: str | None = None, ) -> ase.Atoms:And thread it to the runner:
- _run_packmol(packmol, tmpdir / "pack.inp", tmpdir, verbose) + _run_packmol(packmol, tmpdir / "pack.inp", tmpdir, verbose, julia=julia)
🧹 Nitpick comments (1)
rdkit2ase/pack.py (1)
166-189: Docstring: mention julia parameter and fix minor typoAdd docs for the new parameter and correct “jula” → “Julia”.
Apply this diff:
packmol : str, optional The path to the packmol executable, by default "packmol". - When installing packmol via jula, use "packmol.jl". + When installing packmol via Julia, use "packmol.jl". + julia : str | None, optional + Path to the Julia interpreter when using "packmol.jl". + Defaults to the "JULIA" env var or "julia" on PATH.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
rdkit2ase/pack.py(4 hunks)rdkit2ase/utils.py(2 hunks)tests/test_utils.py(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/test_utils.py (1)
rdkit2ase/utils.py (1)
get_packmol_julia_version(226-255)
rdkit2ase/pack.py (1)
rdkit2ase/utils.py (2)
calculate_box_dimensions(71-80)get_packmol_julia_version(226-255)
🪛 Ruff (0.12.2)
rdkit2ase/utils.py
236-236: Starting a process with a partial executable path
(S607)
246-249: Avoid specifying long messages outside the exception class
(TRY003)
252-255: Avoid specifying long messages outside the exception class
(TRY003)
rdkit2ase/pack.py
223-223: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
226-226: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
228-228: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
229-232: Avoid specifying long messages outside the exception class
(TRY003)
⏰ 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). (4)
- GitHub Check: pytest (3.11, ubuntu-latest, 20.15.1)
- GitHub Check: pytest (3.10, ubuntu-latest, 20.15.1)
- GitHub Check: pytest (3.12, ubuntu-latest, 20.15.1)
- GitHub Check: pytest (3.13, ubuntu-latest, 20.15.1)
tests/test_utils.py
Outdated
| def test_get_packmol_julia_version(): | ||
| """Test the retrieval of the Packmol version when using Julia.""" | ||
| version = get_packmol_julia_version() | ||
| assert version == "v0.1.12" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid brittle version pin; skip if Julia missing and validate via regex
Asserting an exact Packmol.jl version will be flaky across environments and time. Also skip when Julia isn’t available on CI/dev machines.
Apply this diff:
-def test_get_packmol_julia_version():
- """Test the retrieval of the Packmol version when using Julia."""
- version = get_packmol_julia_version()
- assert version == "v0.1.12"
+def test_get_packmol_julia_version(monkeypatch):
+ """Test retrieval of Packmol version via Julia (environment-agnostic)."""
+ import os, re, shutil
+ julia = os.environ.get("JULIA", "julia")
+ if shutil.which(julia) is None:
+ pytest.skip("Julia not available")
+ version = get_packmol_julia_version(julia=julia)
+ assert re.fullmatch(r"v\d+\.\d+\.\d+(?:[+-].+)?", version)Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In tests/test_utils.py around lines 252 to 255, the test currently asserts an
exact Packmol.jl version which is brittle and will fail when Julia is not
present; change it to skip the test when Julia isn't available (e.g., use
pytest.skip or check shutil.which("julia") and call pytest.skip) and replace the
strict equality check with a regex-based assertion such as matching
r"^v\d+\.\d+\.\d+" (or similar) to validate the version format instead of
pinning an exact version.
for more information, see https://pre-commit.ci
Summary by CodeRabbit