fix(detection): preserve class_name string dtype on empty Detections.from_inference - #2270
Merged
Borda merged 10 commits intoMay 27, 2026
Merged
Conversation
…from_inference
For non-empty results, Detections.from_inference stores class_name as a
string array (e.g. <U3 for ["cat"]). On the empty short-circuit path
it instead built {CLASS_NAME_DATA_FIELD: np.empty(0)}, which defaults to
float64. process_roboflow_result already returns a correctly typed empty
data dict ({CLASS_NAME_DATA_FIELD: np.empty(0, dtype=str)}), so assign it
directly instead of rebuilding a wrong-dtype dict.
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a dtype inconsistency in Detections.from_inference so that the class_name data field remains string-typed even when the Roboflow/Inference result contains zero predictions, preventing downstream dtype-mismatch warnings/errors.
Changes:
- Reuse
process_roboflow_result’s returneddatadict in the empty short-circuit path instead of rebuilding it withnp.empty(0)(which defaults tofloat64). - Add a regression test ensuring empty and non-empty inference results produce
class_namearrays of the same string dtype kind.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/supervision/detection/core.py |
Uses process_roboflow_result’s data directly for empty inference results to preserve string dtype. |
tests/detection/test_core.py |
Adds coverage asserting class_name dtype kind matches between empty and non-empty inference outputs. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #2270 +/- ##
=======================================
Coverage 78% 78%
=======================================
Files 66 66
Lines 8412 8416 +4
=======================================
+ Hits 6580 6589 +9
+ Misses 1832 1827 -5 🚀 New features to boost your workflow:
|
…e-dtype Bring PR branch up to date with upstream develop (HeatMapAnnotator divide-by-zero fix, roboflow#2269). --- Co-authored-by: Claude Code <noreply@anthropic.com>
…roboflow_result Update three parametrize entries to use np.empty(0, dtype=str) instead of np.empty(0) for expected class_name on empty-predictions paths. Add explicit dtype equality assertion alongside the existing np.array_equal check so future regressions at the helper layer are caught (np.array_equal is dtype-blind on zero-length arrays). [resolve roboflow#1] /review finding by foundry:qa-specialist (report: .reports/review/2026-05-27T06-06-27Z/review-report.md) --- Co-authored-by: Claude Code <noreply@anthropic.com>
… Returns Callers have no docstring contract for detections.data["class_name"]. Add note to Returns section: field always present as string-dtype array, empty shape (0,) when predictions absent. [resolve roboflow#2] /review finding by foundry:doc-scribe (report: .reports/review/2026-05-27T06-06-27Z/review-report.md) --- Co-authored-by: Claude Code <noreply@anthropic.com>
… and from_vlm paths
from_ultralytics empty path returned cls.empty() with data={} — detections["class_name"]
returned None instead of an empty string array. Same bug in from_vlm Florence-2 branch.
Both now return data={CLASS_NAME_DATA_FIELD: np.empty(0, dtype=str)}, consistent with
the from_inference fix.
[resolve roboflow#3] /review finding by foundry:challenger (report: .reports/review/2026-05-27T06-06-27Z/review-report.md)
---
Co-authored-by: Claude Code <noreply@anthropic.com>
Add null-safety assertion (class_name is not None), full key-set + dtype parity check across all data keys, and concatenation assertion covering the downstream mixed-batch scenario. Replaces single dtype.kind check with structural invariant that guards future key or dtype drift. [resolve roboflow#4] [resolve roboflow#5] [resolve roboflow#8] /review findings by foundry:qa-specialist and foundry:challenger (report: .reports/review/2026-05-27T06-06-27Z/review-report.md) --- Co-authored-by: Claude Code <noreply@anthropic.com>
…_inference No test exercised the duck-typed .dict() object path (the documented Inference SDK usage) for empty predictions. Add test with minimal fake SDK object to confirm the dtype fix applies through the .dict() conversion branch. [resolve roboflow#6] /review finding by foundry:qa-specialist (report: .reports/review/2026-05-27T06-06-27Z/review-report.md) --- Co-authored-by: Claude Code <noreply@anthropic.com>
Function had no docstring. Document: CLASS_NAME_DATA_FIELD always present and string-dtype in returned data dict (load-bearing invariant for the empty-path fix), 6-tuple return order, and an example showing the dtype guarantee. [resolve roboflow#7] /review finding by foundry:doc-scribe (report: .reports/review/2026-05-27T06-06-27Z/review-report.md) --- Co-authored-by: Claude Code <noreply@anthropic.com>
…name
Empty arrays produce <U1 while non-empty "cat" produces <U3; exact dtype
equality was too strict. Kind comparison ("U") is the correct contract.
---
Co-authored-by: Claude Code <noreply@anthropic.com>
Borda
previously approved these changes
May 27, 2026
Simplify example to use inline `>>>` syntax, ensuring clarity and consistency with best practices.
Borda
force-pushed
the
fix/from-inference-empty-class-name-dtype
branch
from
May 27, 2026 08:27
6234178 to
2c8a7ab
Compare
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For non-empty inference results,
Detections.from_inferencestoresclass_nameas a string array (e.g.<U3for["cat"]). On the empty short-circuit path it instead built{CLASS_NAME_DATA_FIELD: np.empty(0)}, which defaults tofloat64. That breaks downstream code that assumes the array is string-typed (e.g.np.isin(det["class_name"], ["cat"])returns a mismatched dtype warning, indexing into a list of names crashes, etc).process_roboflow_resultalready returns a correctly typed empty data dict ({CLASS_NAME_DATA_FIELD: np.empty(0, dtype=str)}on the empty short-circuit, line 71 ofdetection/utils/internal.py). The fix is to use that returneddatadirectly instead of rebuilding a wrong-dtype dict.Minimal repro:
tests/detection/test_core.py::test_from_inference_empty_class_name_dtype_matches_non_emptyasserts both paths produce string-kind arrays.