Skip to content

add a scriptlet to put cuopt_grpc_server on the default path#1100

Open
tmckayus wants to merge 5 commits intoNVIDIA:mainfrom
tmckayus:grpcpath
Open

add a scriptlet to put cuopt_grpc_server on the default path#1100
tmckayus wants to merge 5 commits intoNVIDIA:mainfrom
tmckayus:grpcpath

Conversation

@tmckayus
Copy link
Copy Markdown
Contributor

This changes adds a scriptlet for cuopt_grpc_server so that after installation of the cuopt-server-cuXX packages the binary is on the default path, similar to cuopt_cli.

@tmckayus tmckayus requested a review from a team as a code owner April 14, 2026 16:39
@tmckayus tmckayus requested a review from jakirkham April 14, 2026 16:39
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces a new CLI entry point cuopt_grpc_server that wraps execution of a compiled binary located in the package's bin/ directory. The wrapper delegates command-line arguments via subprocess, and tests validate the entry point's discoverability and basic functionality.

Changes

Cohort / File(s) Summary
gRPC Server CLI Entry Point
python/libcuopt/libcuopt/_grpc_server_wrapper.py, python/libcuopt/pyproject.toml
Added wrapper module with main() function that locates and executes cuopt_grpc_server binary via subprocess, and registered it as console script entry point.
Entry Point Tests
python/cuopt_server/cuopt_server/tests/test_grpc_server_entry_point.py
Added test module validating entry point discoverability via PATH and --help functionality, with runtime dependency probing for libuuid and conditional skip logic.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a scriptlet to make cuopt_grpc_server available on the default PATH.
Description check ✅ Passed The description is directly related to the changeset, explaining that it adds a scriptlet for cuopt_grpc_server to make it available on the default PATH after package installation, similar to cuopt_cli.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@rgsl888prabhu rgsl888prabhu added non-breaking Introduces a non-breaking change improvement Improves an existing functionality labels Apr 14, 2026
Comment thread python/cuopt_server/pyproject.toml Outdated
@tmckayus tmckayus requested a review from a team as a code owner April 14, 2026 19:28
@tmckayus tmckayus requested a review from Iroy30 April 14, 2026 19:28
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@python/cuopt_server/cuopt_server/tests/test_grpc_server_entry_point.py`:
- Around line 14-26: The test_cuopt_grpc_server_help currently calls
subprocess.run on the bare "cuopt_grpc_server" and only checks stdout, which can
raise FileNotFoundError and miss help output printed to stderr; update the test
to first locate the executable with shutil.which("cuopt_grpc_server") and call
pytest.skip if not found, or alternatively invoke the module via sys.executable
-m if an importable entrypoint exists, then call subprocess.run with
stderr=subprocess.STDOUT (or combine stdout/stderr) and a controlled env (e.g.,
env=os.environ.copy() with GPU vars like CUDA_VISIBLE_DEVICES cleared) so the
call is stream-agnostic and environment-isolated, and assert on the combined
output and returncode.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9c80b148-7cb0-405c-b790-842b0fdb0941

📥 Commits

Reviewing files that changed from the base of the PR and between 2d48c97 and 714fa48.

📒 Files selected for processing (4)
  • conda/recipes/cuopt-server/recipe.yaml
  • python/cuopt_server/cuopt_server/_grpc_server_wrapper.py
  • python/cuopt_server/cuopt_server/tests/test_grpc_server_entry_point.py
  • python/cuopt_server/pyproject.toml
✅ Files skipped from review due to trivial changes (1)
  • python/cuopt_server/pyproject.toml

Comment thread python/cuopt_server/cuopt_server/_grpc_server_wrapper.py Outdated
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@python/libcuopt/libcuopt/_grpc_server_wrapper.py`:
- Around line 13-16: The code currently constructs server_path and calls
subprocess.call([server_path] + sys.argv[1:]) which will raise a traceback if
the binary is missing or not executable; update the wrapper to first check
server_path exists and is executable (use os.path.exists/server_path and
os.access(server_path, os.X_OK)), and if not, write a clear error message to
stderr and exit with a non‑zero code; additionally wrap the subprocess.call
invocation in a try/except to catch OSError/CalledProcessError and print the
captured error details before calling sys.exit(1) so failures are reported
cleanly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ddac6bf-6c79-4a56-a8fd-ca3fae24b360

📥 Commits

Reviewing files that changed from the base of the PR and between 1d3fa00 and acf7b80.

📒 Files selected for processing (3)
  • python/cuopt_server/cuopt_server/tests/test_grpc_server_entry_point.py
  • python/libcuopt/libcuopt/_grpc_server_wrapper.py
  • python/libcuopt/pyproject.toml
✅ Files skipped from review due to trivial changes (1)
  • python/cuopt_server/cuopt_server/tests/test_grpc_server_entry_point.py

Comment on lines +13 to +16
server_path = os.path.join(
os.path.dirname(__file__), "bin", "cuopt_grpc_server"
)
sys.exit(subprocess.call([server_path] + sys.argv[1:]))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle missing/non-executable binary gracefully.

On Line 16, a missing or non-executable binary will surface as a Python traceback. Add an explicit guard and exit with a clear error message.

Suggested hardening patch
 def main():
@@
     server_path = os.path.join(
         os.path.dirname(__file__), "bin", "cuopt_grpc_server"
     )
-    sys.exit(subprocess.call([server_path] + sys.argv[1:]))
+    if not os.path.isfile(server_path) or not os.access(server_path, os.X_OK):
+        print(
+            f"cuopt_grpc_server binary not found or not executable: {server_path}",
+            file=sys.stderr,
+        )
+        sys.exit(127)
+    sys.exit(subprocess.call([server_path] + sys.argv[1:]))
🧰 Tools
🪛 Ruff (0.15.10)

[error] 16-16: subprocess call: check for execution of untrusted input

(S603)


[warning] 16-16: Consider [server_path, *sys.argv[1:]] instead of concatenation

Replace with [server_path, *sys.argv[1:]]

(RUF005)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/libcuopt/libcuopt/_grpc_server_wrapper.py` around lines 13 - 16, The
code currently constructs server_path and calls subprocess.call([server_path] +
sys.argv[1:]) which will raise a traceback if the binary is missing or not
executable; update the wrapper to first check server_path exists and is
executable (use os.path.exists/server_path and os.access(server_path, os.X_OK)),
and if not, write a clear error message to stderr and exit with a non‑zero code;
additionally wrap the subprocess.call invocation in a try/except to catch
OSError/CalledProcessError and print the captured error details before calling
sys.exit(1) so failures are reported cleanly.

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.

♻️ Duplicate comments (1)
python/libcuopt/libcuopt/_grpc_server_wrapper.py (1)

13-16: ⚠️ Potential issue | 🟡 Minor

Handle missing binary and spawn failures with explicit user-facing errors.

If the packaged binary is missing/non-executable (or execve fails), this currently produces a Python traceback instead of a clear CLI error. Please add a guard + OSError handling before exiting.

Suggested patch
 def main():
@@
     server_path = os.path.join(
         os.path.dirname(__file__), "bin", "cuopt_grpc_server"
     )
-    sys.exit(subprocess.call([server_path] + sys.argv[1:]))
+    if not os.path.isfile(server_path) or not os.access(server_path, os.X_OK):
+        print(
+            f"cuopt_grpc_server binary not found or not executable: {server_path}",
+            file=sys.stderr,
+        )
+        sys.exit(127)
+    try:
+        sys.exit(subprocess.call([server_path, *sys.argv[1:]]))
+    except OSError as exc:
+        print(f"failed to execute cuopt_grpc_server: {exc}", file=sys.stderr)
+        sys.exit(1)
#!/bin/bash
set -euo pipefail

# Verify whether grpc wrapper has existence/X_OK checks and spawn error handling.
nl -ba python/libcuopt/libcuopt/_grpc_server_wrapper.py | sed -n '1,120p'
echo
rg -n 'os\.path\.(exists|isfile)|os\.access|try:|except OSError|subprocess\.(call|run)' \
  python/libcuopt/libcuopt/_grpc_server_wrapper.py
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/libcuopt/libcuopt/_grpc_server_wrapper.py` around lines 13 - 16, The
wrapper should check that server_path (constructed in this file) exists and is
executable before attempting to spawn it, and wrap the subprocess invocation
(currently using subprocess.call and sys.exit) in a try/except that catches
OSError (and optionally subprocess.SubprocessError) to emit a clear user-facing
error (to stderr or via logging) and exit with a non-zero status; update the
code around server_path, subprocess.call(...) and sys.exit(...) to perform
os.path.exists/os.access checks and handle spawn failures with a descriptive
OSError message including server_path and the underlying exception.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@python/libcuopt/libcuopt/_grpc_server_wrapper.py`:
- Around line 13-16: The wrapper should check that server_path (constructed in
this file) exists and is executable before attempting to spawn it, and wrap the
subprocess invocation (currently using subprocess.call and sys.exit) in a
try/except that catches OSError (and optionally subprocess.SubprocessError) to
emit a clear user-facing error (to stderr or via logging) and exit with a
non-zero status; update the code around server_path, subprocess.call(...) and
sys.exit(...) to perform os.path.exists/os.access checks and handle spawn
failures with a descriptive OSError message including server_path and the
underlying exception.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 64463483-a778-4bbf-a846-f40b409d4840

📥 Commits

Reviewing files that changed from the base of the PR and between acf7b80 and 995a8b1.

📒 Files selected for processing (3)
  • python/cuopt_server/cuopt_server/tests/test_grpc_server_entry_point.py
  • python/libcuopt/libcuopt/_grpc_server_wrapper.py
  • python/libcuopt/pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (2)
  • python/libcuopt/pyproject.toml
  • python/cuopt_server/cuopt_server/tests/test_grpc_server_entry_point.py

this is necessary for cuopt_grpc_server binary to be visible in CI
on amd64
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improves an existing functionality non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants