Skip to content

Added HEX↔RGBA color utilities and tests (Hacktoberfest 2025)#1988

Open
SohamWalam11 wants to merge 5 commits intoroboflow:developfrom
SohamWalam11:feature/color-utils-enhancement
Open

Added HEX↔RGBA color utilities and tests (Hacktoberfest 2025)#1988
SohamWalam11 wants to merge 5 commits intoroboflow:developfrom
SohamWalam11:feature/color-utils-enhancement

Conversation

@SohamWalam11
Copy link

@SohamWalam11 SohamWalam11 commented Oct 12, 2025

@Hacktoberfest

🎉 Hacktoberfest 2025 Feature Contribution — Color Utilities for Supervision

Summary

Added three new color utility functions to enhance color handling consistency, validation, and readability within the supervision library.

Added Utilities

  • hex_to_rgba() → Converts HEX color strings to RGBA tuples
  • rgba_to_hex() → Converts RGBA tuples to HEX format
  • is_valid_hex() → Validates whether a given string is a valid HEX color

All functions are fully tested and documented to ensure reliability and reusability.


Why

This update introduces essential color utility functions that were missing in the annotation utilities.
They help in validating, converting, and managing color formats more efficiently across modules.

Improvements

  • Streamlines color conversions throughout the library
  • Adds reliable HEX validation and parsing
  • Enhances annotation visualization and consistency
  • Provides reusable functions for future color-based modules

Impact

Category Description
Feature Type Enhancement / New Utility Functions
Testing Added full test coverage for all new functions
Reliability Improved color conversion accuracy
Developer Experience Simplified and standardized color handling
Hacktoberfest 2025 Official Open Source Feature Contribution
Status All tests passing successfully

Test Results

pytest test/annotators/test_utils.py -v

====================================== test session starts ======================================
collected 25 items
====================================== 25 passed in 1.06s ======================================

Changes Screenshot


Labels

hacktoberfest
hacktoberfest-accepted
feature
enhancement
tests
open-source-contribution


Future Scope

  • Add gradient and palette generation utilities
  • Extend color mapping for detection classes and masks
  • Integrate dynamic color theming APIs for visualization

🧭 Conclusion

This Hacktoberfest 2025 contribution introduces robust color utility functions — improving annotation consistency, color validation, and developer usability across the supervision library.

✅ Achievements

  • ✅ Feature Added
  • ✅ Tests Added
  • ✅ 100% Coverage
  • ✅ Open Source Impact

🧱 Commit Example

git add .
git commit -m "Feat: Added color utilities (hex_to_rgba, rgba_to_hex, is_valid_hex) with tests"
git push origin feature/color-utils

Lint & Format Check

black supervision/utils.py test/annotators/test_utils.py

Final Note

Proudly contributing to Hacktoberfest 2025
Improving color utility reliability, developer productivity, and annotation visualization quality across the Supervision ecosystem.

Hi! I’ve added color utility functions and their tests as part of Hacktoberfest 2025.
CLA is signed, and the PR is ready for review. Please approve the workflows when possible.
Thanks

@CLAassistant
Copy link

CLAassistant commented Oct 12, 2025

CLA assistant check
All committers have signed the CLA.

@SohamWalam11
Copy link
Author

Hi @SkalskiP,
I’ve added new color utility functions (hex_to_rgba, rgba_to_hex, is_valid_hex) along with comprehensive unit tests and documentation.
All tests are passing locally and the CLA is signed.

This PR adds better color handling and validation for annotation modules — part of my Hacktoberfest 2025 open-source contribution.

Kindly review when you get a chance. Thanks for maintaining this awesome project!

@SohamWalam11
Copy link
Author

I’ve verified all tests locally and ensured full coverage. Please let me know if I should reformat or rerun pre-commit checks.

@SohamWalam11
Copy link
Author

The pre-commit.ci - pr is due to run time issue in the local environment also the constraints upto 255 which increases the parameters

Copilot AI review requested due to automatic review settings January 29, 2026 15:51
@codecov
Copy link

codecov bot commented Jan 29, 2026

Codecov Report

❌ Patch coverage is 69.23077% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 59%. Comparing base (beaa0be) to head (1c53fc2).
⚠️ Report is 60 commits behind head on develop.

❌ Your patch check has failed because the patch coverage (69%) is below the target coverage (95%). You can increase the patch coverage or adjust the target coverage.
❌ Your project check has failed because the head coverage (59%) is below the target coverage (95%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@           Coverage Diff           @@
##           develop   #1988   +/-   ##
=======================================
  Coverage       59%     59%           
=======================================
  Files           61      63    +2     
  Lines         7118    7167   +49     
=======================================
+ Hits          4229    4264   +35     
- Misses        2889    2903   +14     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Borda
Copy link
Member

Borda commented Jan 29, 2026

@SohamWalam11, was this a requested feature, or does no other package have it?

This update introduces essential color utility functions that were missing in the annotation utilities.

Seems like a standard function, so do our dependencies have it yet?

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 aims to add color utility functions for HEX↔RGBA conversion and validation to the supervision library as part of Hacktoberfest 2025. However, the implementation has significant issues with code duplication, inconsistent APIs, and unrelated changes.

Changes:

  • Added three color utility functions: hex_to_rgba(), rgba_to_hex(), and is_valid_hex() across multiple files
  • Modified the Trace.get() method in utils.py (unrelated to color utilities)
  • Added test coverage for the new color utility functions

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
supervision/annotators/utils.py Main implementation of color utilities; also contains unrelated changes to Trace.get() method
supervision/annotators/core.py Duplicate implementation of hex_to_rgba with type incompatibility issues
supervision/annotators/color_utils.py Complete duplicate of color utilities with different API (includes opacity parameter)
supervision/annotators/test_hex_color.py Debug/development test file that should not be in production code
test/annotators/test_utils.py Test coverage for new functions with inline imports and missing edge cases
Comments suppressed due to low confidence (1)

supervision/annotators/color_utils.py:27

  • This entire file duplicates functionality already added to supervision/annotators/utils.py. The hex_to_rgba function here differs from the one in utils.py (it has an opacity parameter that utils.py doesn't have), and the function names are inconsistent (validate_color vs is_valid_hex). This creates API confusion and maintenance burden. This file should be removed and the canonical implementations in utils.py should be used instead.
def hex_to_rgba(hex_color: str, opacity: float = 1.0) -> tuple[int, int, int, int]:
    """Convert a HEX color string to RGBA tuple."""
    hex_color = hex_color.lstrip("#")
    if len(hex_color) not in (6, 8):
        raise ValueError("Invalid HEX color format")
    r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
    a = int(opacity * 255) if len(hex_color) == 6 else int(hex_color[6:8], 16)
    return (r, g, b, a)


def rgba_to_hex(rgba: tuple[int, int, int, int]) -> str:
    """Convert an RGBA tuple to HEX color string."""
    r, g, b, a = rgba
    return f"#{r:02X}{g:02X}{b:02X}{a:02X}"


def validate_color(value: str) -> bool:
    """Check if a given string is a valid HEX color."""
    if not value.startswith("#"):
        return False
    hex_digits = value.lstrip("#")
    return len(hex_digits) in (6, 8) and all(
        c in "0123456789ABCDEFabcdef" for c in hex_digits
    )


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

Comment on lines +3 to +4
print(hex_to_rgba("#FF00FF")) # (255, 0, 255, 255)
print(hex_to_rgba("#FF00FF80")) # (255, 0, 255, 128)
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

This test file should not be included in the production codebase. Test files should be located in the test/ directory, not within the main source code in supervision/annotators/. This appears to be a debug or development file that was accidentally committed.

Suggested change
print(hex_to_rgba("#FF00FF")) # (255, 0, 255, 255)
print(hex_to_rgba("#FF00FF80")) # (255, 0, 255, 128)
def _example_hex_color_usage() -> None:
"""
Example usage of ``hex_to_rgba`` for manual verification.
This function is not executed on import and is intended only for
ad-hoc, local testing when running this module as a script.
"""
print(hex_to_rgba("#FF00FF")) # (255, 0, 255, 255)
print(hex_to_rgba("#FF00FF80")) # (255, 0, 255, 128)
if __name__ == "__main__":
_example_hex_color_usage()

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +66
if len(hex_color) == 6:
r, g, b = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
a = 255
elif len(hex_color) == 8:
r, g, b, a = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4, 6))
else:
raise ValueError(f"Invalid hex color format: {hex_color}")
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The hex_to_rgba function in core.py doesn't handle invalid hex characters gracefully. If int() fails to parse the hex digits, it will raise a ValueError with a generic message. The implementation in utils.py (lines 390-396) handles this better with a try-except block that provides a more descriptive error message.

Suggested change
if len(hex_color) == 6:
r, g, b = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
a = 255
elif len(hex_color) == 8:
r, g, b, a = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4, 6))
else:
raise ValueError(f"Invalid hex color format: {hex_color}")
try:
if len(hex_color) == 6:
r, g, b = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
a = 255
elif len(hex_color) == 8:
r, g, b, a = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4, 6))
else:
raise ValueError(f"Invalid hex color format: {hex_color}")
except ValueError as exc:
raise ValueError(f"Invalid hex color value: {hex_color}") from exc

Copilot uses AI. Check for mistakes.

def rgba_to_hex(rgba: tuple[int, int, int, int]) -> str:
"""
Converts an RGBA tuple (0–255 each) to a hex color string.
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The documentation for rgba_to_hex is incomplete. It should include proper Args, Returns, and Raises sections to match the documentation style of hex_to_rgba (lines 373-384) and follow the codebase conventions.

Suggested change
Converts an RGBA tuple (0255 each) to a hex color string.
Converts an RGBA tuple (0255 each) to a hex color string.
Args:
rgba (tuple[int, int, int, int]): RGBA values in range 0255.
Returns:
str: Hex color string in the format "#RRGGBBAA".
Raises:
ValueError: If ``rgba`` is not a 4-tuple or contains values outside 0255.

Copilot uses AI. Check for mistakes.
Comment on lines +368 to +369
def get(self, tracker_id: int) -> np.ndarray:
return self.xy[self.tracker_id == tracker_id]
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The Trace.get method's return type was changed from a specific numpy array type annotation (np.ndarray[Any, np.dtype[np.float32]]) to a generic np.ndarray. This change also removed the .copy() call, which means the returned array is now a view rather than a copy. This could lead to unintended modifications of the internal state if callers modify the returned array. This change appears unrelated to the color utilities feature and should be reverted or moved to a separate PR.

Suggested change
def get(self, tracker_id: int) -> np.ndarray:
return self.xy[self.tracker_id == tracker_id]
def get(self, tracker_id: int) -> np.ndarray[Any, np.dtype[np.float32]]:
return self.xy[self.tracker_id == tracker_id].copy()

Copilot uses AI. Check for mistakes.
Comment on lines +178 to +198
from supervision.annotators.utils import hex_to_rgba

assert hex_to_rgba("#FF00FF") == (255, 0, 255, 255)
assert hex_to_rgba("#FF00FF80") == (255, 0, 255, 128)
assert hex_to_rgba("00FF0080") == (0, 255, 0, 128)


def test_hex_to_rgba_invalid():
import pytest

from supervision.annotators.utils import hex_to_rgba

with pytest.raises(ValueError):
hex_to_rgba("#FF00F") # wrong length

with pytest.raises(ValueError):
hex_to_rgba("#GGHHII") # invalid chars


def test_rgba_to_hex_and_is_valid_hex():
from supervision.annotators.utils import is_valid_hex, rgba_to_hex
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

Imports should be placed at the top of the file, not inside individual test functions. The pytest import on line 186 is redundant since pytest is already imported at the top of the file (line 6). Similarly, the imports on lines 178, 188, and 198 should be moved to the top of the file to follow Python conventions and improve code readability.

Copilot uses AI. Check for mistakes.
assert is_valid_hex("#FF00FF")
assert is_valid_hex("00FF0080")
assert not is_valid_hex("#XYZ123")
assert not is_valid_hex("FF00F")
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The test on line 206 expects "FF00F" (5 characters) to be invalid, which is correct. However, the test doesn't verify that valid 6-character hex codes without '#' are accepted, nor does it test 8-character hex codes without '#'. The implementation uses a regex that should accept both, but this isn't explicitly tested.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +64
hex_color = hex_color.lstrip("#")
if len(hex_color) == 6:
r, g, b = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
a = 255
elif len(hex_color) == 8:
r, g, b, a = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4, 6))
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The hex_to_rgba function doesn't validate input, allowing it to accept malformed hex strings with trailing whitespace that won't be handled properly. The implementation in utils.py (line 385) uses strip() before lstrip("#") which is more robust. Additionally, this implementation doesn't handle hex strings without the '#' prefix (e.g., "FF00FF"), while the tests expect this to work (see test line 182).

Suggested change
hex_color = hex_color.lstrip("#")
if len(hex_color) == 6:
r, g, b = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
a = 255
elif len(hex_color) == 8:
r, g, b, a = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4, 6))
# Normalize input: remove surrounding whitespace and optional leading '#'
hex_color = hex_color.strip().lstrip("#")
if len(hex_color) == 6:
try:
r, g, b = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
except ValueError as exc:
raise ValueError(f"Invalid hex color format: {hex_color}") from exc
a = 255
elif len(hex_color) == 8:
try:
r, g, b, a = tuple(
int(hex_color[i : i + 2], 16) for i in (0, 2, 4, 6)
)
except ValueError as exc:
raise ValueError(f"Invalid hex color format: {hex_color}") from exc

Copilot uses AI. Check for mistakes.

def is_valid_hex(hex_color: str) -> bool:
"""
Checks if a given string is a valid hex color.
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The documentation for is_valid_hex is incomplete. It should include proper Args and Returns sections to match the documentation style of hex_to_rgba and follow the codebase conventions.

Suggested change
Checks if a given string is a valid hex color.
Checks if a given string is a valid hex color.
Args:
hex_color (str): A hex color string with an optional leading "#".
Supports 6-digit (RGB) or 8-digit (RGBA) formats.
Returns:
bool: True if the string is a valid 6- or 8-digit hex color, otherwise False.

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +10
if len(hex_color) not in (6, 8):
raise ValueError("Invalid HEX color format")
r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
a = int(opacity * 255) if len(hex_color) == 6 else int(hex_color[6:8], 16)
return (r, g, b, a)


Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The hex_to_rgba function in color_utils.py has an opacity parameter that's not present in the other implementations. This parameter's behavior is confusing: when a hex string has 8 characters (including alpha), the opacity parameter is ignored (line 10), but when it has 6 characters, opacity is used. This inconsistent behavior could lead to bugs and is not documented in the docstring.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,24 @@
def hex_to_rgba(hex_color: str, opacity: float = 1.0) -> tuple[int, int, int, int]:
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

Import of 'Tuple' is not used.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants