Skip to content

Conversation

@carlosgjs
Copy link
Collaborator

@carlosgjs carlosgjs commented Nov 5, 2025

Summary

Management command for testing a single image job + small dev tooling improvements

List of Changes

  • Management command
  • Updates to docker and git ignore files
  • Configuration to debug the django container

Test run:

docker compose run --rm django python manage.py process_single_image 39750 --pipeline 11 --wait

WARN[0000] Found orphan containers ([ami_local_nats]) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up. 
[+] Creating 5/5
 ✔ Container ami_local_redis        Running                                                                                  0.0s 
 ✔ Container antenna-postgres-1     Running                                                                                  0.0s 
 ✔ Container antenna-ml_backend-1   Running                                                                                  0.0s 
 ✔ Container antenna-minio-1        Running                                                                                  0.0s 
 ✔ Container antenna-minio-proxy-1  Running                                                                                  0.0s 
[+] Running 1/1
 ✔ Container antenna-minio-init-1  Started                                                                                   0.1s 
PostgreSQL is available
✓ Found image: quebec/belislelab/PM6/20250803/._P8030036.JPG
  Project: Test Project 6832e6e6
  Deployment: AMI
✓ Using pipeline: Moth / Non-Moth Classifier (v1)

Submitting job...
INFO 2025-11-05 14:16:36,356 utils 1 281473846619456 Created job 11 for single image 39750 with pipeline Moth / Non-Moth Classifier (id: 11)
WARNING 2025-11-05 14:16:36,372 models 1 281473846619456 Job #11 "Single image 39750 - Moth / Non-Moth Classifier" (PENDING) status mismatches progress: CREATED != PENDING
INFO 2025-11-05 14:16:36,372 utils 1 281473846619456 Job 11 enqueued with task_id: d590c2f3-4d37-401d-b6cf-aa46ef61cf96
✓ Job 11 created and enqueued
  Task ID: d590c2f3-4d37-401d-b6cf-aa46ef61cf96
  Status: PENDING
  Name: Single image 39750 - Moth / Non-Moth Classifier

Waiting for job to complete...
(Press Ctrl+C to stop waiting)
  Status: SUCCESS         | Progress:  33.3% | Elapsed:    2.0s

✓ Job completed successfully in 2.0s

Results:
  Detections created: 0

Job ID: 11
  • I have tested these changes appropriately.
  • I have added and/or modified relevant tests.
  • I updated relevant documentation or comments.
  • I have verified that this PR follows the project's coding standards.
  • Any dependent changes have already been merged to main.

Summary by CodeRabbit

  • New Features

    • Added a command to submit and optionally wait for processing of a single image with live progress and final results.
  • Documentation

    • Added usage guide and examples for the new image processing command.
  • Bug Fixes

    • Made project selection more robust when handling request data to avoid errors in some request types.
  • Chores

    • Expanded ignore rules for runtimes, build artifacts, editors/OS files; added huggingface cache to ignore.
    • Improved local debug configurations and exposed an additional debug port.

@netlify
Copy link

netlify bot commented Nov 5, 2025

Deploy Preview for antenna-preview canceled.

Name Link
🔨 Latest commit 521f4c4
🔍 Latest deploy log https://app.netlify.com/projects/antenna-preview/deploys/6916a2684a02bf000810e9fa

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Warning

Rate limit exceeded

@mihow has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 55 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 d503284 and 521f4c4.

📒 Files selected for processing (3)
  • .gitignore (1 hunks)
  • .vscode/launch.json (1 hunks)
  • docker-compose.yml (1 hunks)

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This PR expands ignore patterns (.dockerignore, .gitignore), updates VSCode launch profiles, adds a Django management command to process a single image with optional polling, fixes robust POST data handling in a view, and exposes port 5679 in docker-compose for debugging.

Changes

Cohort / File(s) Summary
Ignore files
\.dockerignore, \.gitignore
.dockerignore rewritten to use directory-style patterns and expanded entries for Python caches/builds, virtualenvs, Node/docs/UI artifacts, VCS/IDE/OS files, and Docker artifacts; .gitignore adds a "huggingface cache" header and huggingface_cache/.
VSCode & Docker Compose
\.vscode/launch.json, docker-compose.yml
.vscode/launch.json updates launch configs: renamed default to "Current File", adds debugpy launch for current file, adds "Django attach" (host: localhost, port: 5679) and renames Celery attach to "Celery worker attach" with pathMappings; docker-compose.yml exposes 5679:5679 on the django service and adds debug-related comments and a minor healthcheck formatting tweak.
Django management command
ami/jobs/management/commands/process_single_image.py, ami/jobs/management/commands/README.md
New management command process_single_image with README: accepts image_id, --pipeline, and --wait; validates image/pipeline/deployment/project, submits processing job, optionally polls status with live progress and interrupt handling, and prints final summaries including detections/classifications.
Application logic fix
ami/base/views.py
get_active_project now guards access to request.data by using post_data = request.data if isinstance(request.data, dict) else {} before calling .get(), preserving query-param precedence.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as manage.py
    participant Cmd as process_single_image.Command
    participant DB as Database
    participant Queue as Job Queue
    participant Poller as Poller

    User->>CLI: run process_single_image <image_id> --pipeline <id> [--wait]
    CLI->>Cmd: invoke handle()
    Cmd->>DB: validate SourceImage, Deployment, Project, Pipeline
    DB-->>Cmd: return entities
    Cmd->>Queue: submit job (process_single_source_image)
    Queue-->>Cmd: return job (pk, task_id, status)
    alt --wait provided
        Cmd->>Poller: start polling loop (interval ~2s)
        loop while not complete
            Poller->>Queue: fetch job status/progress
            Queue-->>Poller: status/progress
            Poller->>User: stream progress & elapsed time
        end
        Poller->>DB: fetch Detections / Classifications
        DB-->>User: final results summary
    else no --wait
        Cmd->>User: print job created and tip to check status later
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing careful review:
    • ami/jobs/management/commands/process_single_image.py — job submission, polling loop, interrupt handling, progress display, and result retrieval.
    • ami/base/views.py — ensure request.data handling is compatible with frameworks used (DRF vs Django Request).
    • .vscode/launch.json and docker-compose.yml — verify debug ports, paths, and that the new launch configs match runtime expectations.
    • .dockerignore — confirm no required files are accidentally ignored.

"I hopped through ignores and launch configs bright,
Opened a port to let debuggers alight,
A command to process one image at a time,
I polled and I printed, then finished—sublime! 🥕✨"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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
Title check ✅ Passed Title accurately captures the main change: developer tooling improvements for testing ML jobs, covering the management command and configuration updates.
Description check ✅ Passed Description includes summary, list of changes, and test run output demonstrating functionality. However, it lacks detailed explanation of changes and deployment notes.

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.

@carlosgjs carlosgjs requested a review from mihow November 5, 2025 19:17
@carlosgjs carlosgjs marked this pull request as ready for review November 5, 2025 19:17
Copilot AI review requested due to automatic review settings November 5, 2025 19:17
Copy link
Contributor

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 adds debugging and testing utilities for processing individual images through ML pipelines. It includes Docker configuration for remote debugging, a management command for single-image processing, and a utility function to programmatically submit jobs.

  • Added submit_single_image_job utility function and process_single_image management command for testing/debugging pipelines on individual images
  • Configured Docker and VSCode for remote debugging with debugpy on port 5679
  • Enhanced .dockerignore with comprehensive patterns and fixed request.data handling for non-dict types

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
ami/jobs/utils.py New utility function for submitting single-image jobs
ami/jobs/management/commands/process_single_image.py New Django management command for processing individual images with progress monitoring
ami/jobs/management/commands/README.md Documentation for the new management command
ami/base/views.py Fixed potential TypeError when request.data is not a dict
docker-compose.yml Added debugpy port mapping and debugging command example
.vscode/launch.json Added debug configurations for Django and Celery worker attachment
.gitignore Added huggingface_cache directory exclusion
.dockerignore Enhanced with comprehensive patterns and removed duplicate entries

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

Copy link
Contributor

@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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58af519 and ace6146.

📒 Files selected for processing (8)
  • .dockerignore (1 hunks)
  • .gitignore (1 hunks)
  • .vscode/launch.json (1 hunks)
  • ami/base/views.py (1 hunks)
  • ami/jobs/management/commands/README.md (1 hunks)
  • ami/jobs/management/commands/process_single_image.py (1 hunks)
  • ami/jobs/utils.py (1 hunks)
  • docker-compose.yml (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
ami/jobs/utils.py (1)
ami/jobs/models.py (3)
  • MLJob (316-513)
  • logger (989-998)
  • enqueue (801-818)
ami/jobs/management/commands/process_single_image.py (2)
ami/jobs/utils.py (1)
  • submit_single_image_job (12-78)
ami/main/models.py (1)
  • Classification (2207-2351)
ami/base/views.py (1)
ami/main/api/views.py (1)
  • get (1626-1682)
🪛 Ruff (0.14.3)
ami/jobs/utils.py

40-40: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


47-47: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

ami/jobs/management/commands/process_single_image.py

44-44: Unused method argument: args

(ARG002)


58-58: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


58-58: Avoid specifying long messages outside the exception class

(TRY003)


65-65: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


65-65: Avoid specifying long messages outside the exception class

(TRY003)


77-77: Do not catch blind exception: Exception

(BLE001)


78-78: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


78-78: Avoid specifying long messages outside the exception class

(TRY003)


78-78: Use explicit conversion flag

Replace with conversion flag

(RUF010)


161-161: Unused noqa directive (non-enabled: E221)

Remove unused noqa directive

(RUF100)

Copy link
Contributor

@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: 2

🧹 Nitpick comments (1)
ami/jobs/utils.py (1)

40-40: Consider using logging.exception for better debugging context.

Since exceptions are re-raised, logging.exception would automatically include the traceback, making debugging easier for this testing/debugging utility.

Apply this diff:

     except SourceImage.DoesNotExist:
-        logger.error(f"SourceImage with id {image_id} does not exist")
+        logger.exception(f"SourceImage with id {image_id} does not exist")
         raise

     # Fetch the pipeline and validate it exists
@@
     except Pipeline.DoesNotExist:
-        logger.error(f"Pipeline with id {pipeline_id} does not exist")
+        logger.exception(f"Pipeline with id {pipeline_id} does not exist")
         raise

Also applies to: 47-47

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ace6146 and 7cdf209.

📒 Files selected for processing (3)
  • .dockerignore (1 hunks)
  • ami/jobs/management/commands/process_single_image.py (1 hunks)
  • ami/jobs/utils.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .dockerignore
🧰 Additional context used
🧬 Code graph analysis (2)
ami/jobs/utils.py (1)
ami/jobs/models.py (3)
  • MLJob (316-513)
  • logger (989-998)
  • enqueue (801-818)
ami/jobs/management/commands/process_single_image.py (2)
ami/jobs/utils.py (1)
  • submit_single_image_job (12-72)
ami/main/models.py (1)
  • Classification (2207-2351)
🪛 Ruff (0.14.3)
ami/jobs/utils.py

40-40: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


47-47: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

ami/jobs/management/commands/process_single_image.py

44-44: Unused method argument: args

(ARG002)


55-57: Avoid specifying long messages outside the exception class

(TRY003)


62-62: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


62-62: Avoid specifying long messages outside the exception class

(TRY003)


69-69: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


69-69: Avoid specifying long messages outside the exception class

(TRY003)


82-82: Do not catch blind exception: Exception

(BLE001)


83-83: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


83-83: Avoid specifying long messages outside the exception class

(TRY003)


83-83: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ 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). (1)
  • GitHub Check: test
🔇 Additional comments (2)
ami/jobs/management/commands/process_single_image.py (2)

52-62: Good defensive programming for deployment validation.

The explicit check for missing deployment/project (lines 54-57) correctly prevents the AttributeError that past reviews flagged, and provides a clear, actionable error message.


100-167: Well-implemented wait/poll logic with good UX.

The polling loop includes thoughtful details: defensive None checks for the progress chain (lines 112-115), update throttling to avoid spam (line 119), graceful KeyboardInterrupt handling (lines 135-139), and informative result summaries. The implementation provides a smooth user experience for this testing/debugging tool.

Copy link
Contributor

@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

🧹 Nitpick comments (1)
ami/jobs/management/commands/process_single_image.py (1)

127-153: LGTM!

The results display provides helpful information for each completion scenario. The late import of Classification at line 141 works but could be moved to the top-level imports for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cdf209 and 1dfac9e.

📒 Files selected for processing (1)
  • ami/jobs/management/commands/process_single_image.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ami/jobs/management/commands/process_single_image.py (2)
ami/ml/orchestration/processing.py (1)
  • process_single_source_image (11-45)
ami/main/models.py (1)
  • Classification (2207-2351)
🪛 Ruff (0.14.4)
ami/jobs/management/commands/process_single_image.py

32-32: Unused method argument: args

(ARG002)


41-43: Avoid specifying long messages outside the exception class

(TRY003)


48-48: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


48-48: Avoid specifying long messages outside the exception class

(TRY003)


55-55: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


55-55: Avoid specifying long messages outside the exception class

(TRY003)


68-68: Do not catch blind exception: Exception

(BLE001)


69-69: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


69-69: Avoid specifying long messages outside the exception class

(TRY003)


69-69: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ 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). (1)
  • GitHub Check: test
🔇 Additional comments (7)
ami/jobs/management/commands/process_single_image.py (7)

1-16: LGTM!

The imports and class setup are appropriate for a Django management command.


18-30: LGTM!

The command arguments are well-defined with appropriate types and help text.


38-48: LGTM!

The image validation properly checks for deployment/project association as addressed in the previous review, and provides clear error messages.


51-55: LGTM!

The pipeline validation is straightforward and provides helpful output.


71-78: LGTM!

The job creation output provides helpful details for debugging.


80-84: LGTM!

Providing a helpful tip for checking job status when not waiting improves the developer experience.


86-125: LGTM!

The wait loop implementation is solid:

  • Progress checking properly guards against None values (addressing previous review concerns)
  • Display updates only when progress/status changes (efficient)
  • KeyboardInterrupt is handled gracefully
  • Terminal output with \r provides good live feedback

Copy link
Contributor

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1dfac9e and 1976961.

📒 Files selected for processing (1)
  • ami/jobs/management/commands/process_single_image.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ami/jobs/management/commands/process_single_image.py (2)
ami/ml/orchestration/processing.py (1)
  • process_single_source_image (11-45)
ami/main/models.py (1)
  • Classification (2207-2351)
🪛 Ruff (0.14.4)
ami/jobs/management/commands/process_single_image.py

32-32: Unused method argument: args

(ARG002)


42-44: Avoid specifying long messages outside the exception class

(TRY003)


49-49: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


49-49: Avoid specifying long messages outside the exception class

(TRY003)


56-56: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


56-56: Avoid specifying long messages outside the exception class

(TRY003)


68-68: Do not catch blind exception: Exception

(BLE001)


69-69: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


69-69: Avoid specifying long messages outside the exception class

(TRY003)


69-69: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ 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). (1)
  • GitHub Check: test

@carlosgjs carlosgjs requested a review from mihow November 11, 2025 19:05
Copy link
Contributor

@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 (1)
ami/jobs/management/commands/process_single_image.py (1)

49-49: Consider explicit exception chaining for clarity.

Adding from err preserves the original traceback when re-raising, helping debugging. At line 69, you can also use f"{e!s}" instead of str(e).

Apply this pattern:

 except SourceImage.DoesNotExist as err:
-    raise CommandError(f"SourceImage with id {image_id} does not exist")
+    raise CommandError(f"SourceImage with id {image_id} does not exist") from err
 except Pipeline.DoesNotExist as err:
-    raise CommandError(f"Pipeline with id {pipeline_id} does not exist")
+    raise CommandError(f"Pipeline with id {pipeline_id} does not exist") from err
 except Exception as e:
-    raise CommandError(f"Failed to submit job: {str(e)}")
+    raise CommandError(f"Failed to submit job: {e!s}") from e

Also applies to: 56-56, 69-69

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1976961 and d503284.

📒 Files selected for processing (1)
  • ami/jobs/management/commands/process_single_image.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ami/jobs/management/commands/process_single_image.py (2)
ami/ml/orchestration/processing.py (1)
  • process_single_source_image (11-45)
ami/main/models.py (1)
  • Classification (2207-2351)
🪛 Ruff (0.14.4)
ami/jobs/management/commands/process_single_image.py

32-32: Unused method argument: args

(ARG002)


42-44: Avoid specifying long messages outside the exception class

(TRY003)


49-49: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


49-49: Avoid specifying long messages outside the exception class

(TRY003)


56-56: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


56-56: Avoid specifying long messages outside the exception class

(TRY003)


68-68: Do not catch blind exception: Exception

(BLE001)


69-69: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


69-69: Avoid specifying long messages outside the exception class

(TRY003)


69-69: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ 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). (2)
  • GitHub Check: lint
  • GitHub Check: test
🔇 Additional comments (1)
ami/jobs/management/commands/process_single_image.py (1)

1-153: Well-structured debugging command with past issues resolved.

The implementation correctly validates inputs, submits jobs via process_single_source_image, optionally waits with live progress updates, and displays results. Past critical issues (import path, redundant query, deployment check) have been addressed.

@carlosgjs
Copy link
Collaborator Author

TODO @carlosgjs : add a feature flag to re-process all images. Can be either at the project (pydantic) or job level.

Copy link
Collaborator

@mihow mihow left a comment

Choose a reason for hiding this comment

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

@carlosgjs thanks for the fixes and debug tools! I pulled out the debugpy parts and merged them in #1048

@mihow mihow merged commit 231a79a into RolnickLab:main Nov 14, 2025
7 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Nov 18, 2025
5 tasks
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.

2 participants