API Reference

Everything you can do with CM-Colors (the non-scary version)

This is your complete guide to all the functions in CM-Colors. Don’t worry - you probably only need the first one, but the rest are here if you get curious!

class cm_colors.CMColors[source]

Bases: object

CMColors provides a comprehensive API for color accessibility and manipulation. All core functionalities are exposed as methods of this class.

The main CM-Colors class. Create one of these, then use it to tune your colors!

__init__()[source]

Initializes the CMColors instance. Currently, no specific parameters are needed for initialization.

The One You Actually Need

Start here. This is probably all you’ll ever use.

CMColors.tune_colors(text, bg, large_text: bool = False, details: bool = False)[source]

Adjusts the text color to meet WCAG contrast requirements against a background.

Parameters:
  • text (str|tuple) – Text color in any supported format (hex string, rgb(a) string, named color, or RGB tuple).

  • bg (str|tuple) – Background color in any supported format (hex string, rgb(a) string, named color, or RGB tuple).

  • large_text (bool) – True when text is considered large (18pt+ or 14pt+ bold); affects required WCAG level.

  • details (bool) – If True, return a detailed report instead of the simple result tuple.

Returns:

tuple: (tuned_text_rgb_str, is_accessible)

tuned_text_rgb_str (str): Adjusted text color as an ‘rgb(…)’ string. is_accessible (bool): True if the adjusted pair meets at least WCAG AA, False otherwise.

If details is True:
dict: Detailed report with keys:
  • text: original text color input

  • tuned_text: adjusted text color as an ‘rgb(…)’ string

  • bg: background color input

  • large: value of the large_text parameter

  • wcag_level: resulting WCAG compliance level (‘AAA’, ‘AA’, or ‘FAIL’)

  • improvement_percentage: percentage improvement in contrast

  • status: True if wcag_level != ‘FAIL’, False otherwise

  • message: human-readable status message

Return type:

If details is False

What it does: Takes your pretty colors and makes tiny adjustments so everyone can read them.

When to use it: Always! This is the magic function that fixes accessibility problems.

What you get back:

  • Simple mode (default): Just the tuned color and whether it’s accessible

  • Details mode (details=True): Full report with improvement stats and messages

Examples:

# Simple - just get the fixed color
text = "rgb(100, 100, 100)"  # Gray text
background = "rgb(255, 255, 255)"  # White background

tuned_text, is_accessible = cm.tune_colors(text, background)
print(f"Tuned color: {tuned_text}") #"rgb(98, 98, 98)"
print(f"Is accessible: {is_accessible}") #True
# Detailed - get the full report
result = cm.tune_colors(text, background, details=True)
print(f"Tuned color: {result['tuned_text']}")
print(f"WCAG level: {result['wcag_level']}")
print(f"Message: {result['message']}")
print(f"Improvement: {result['improvement_percentage']:.1f}%")
# Large text has different requirements
large_tuned_text, large_accessible = cm.tune_colors(text, background, large_text=True)

Color Checking Functions

For when you want to test your colors before tuning them

CMColors.contrast_ratio(text_color, bg_color) float[source]

Compute the WCAG contrast ratio between two colors.

Parameters:
  • text_color – Text color in any supported format (hex, “rgb(…)”, “rgba(…)”, 3-tuple, named color, etc.).

  • bg_color – Background color in any supported format.

Returns:

The computed contrast ratio between the text and background colors.

Return type:

float

Raises:

ValueError – If either color cannot be parsed or the color pair is invalid.

What it does: Gives you a number that tells you how readable your text is.

The magic numbers:

  • Under 4.5 = Hard to read (needs tuning)

  • 4.5-7.0 = Pretty readable (AA level)

  • Over 7.0 = Super readable (AAA level)

Example:

score = cm.contrast_ratio((80, 80, 80), (255, 255, 255))
print(f"Readability score: {score:.1f}")
# Higher numbers = easier to read

CMColors.wcag_level(text_color, bg_color, large_text: bool = False) str[source]

Determine the WCAG contrast compliance level for a text/background color pair, considering large-text rules.

Parameters:
  • text_color – Text color in any supported format (hex, rgb/rgba string, (r,g,b) tuple, named color, etc.). RGBA colors will be composited as needed.

  • bg_color – Background color in any supported format.

  • large_text (bool) – True when text is considered large (18pt+ or 14pt+ bold), False otherwise.

Returns:

‘AAA’, ‘AA’, or ‘FAIL’ indicating the WCAG compliance level.

Return type:

str

Raises:

ValueError – If one or both colors cannot be parsed or are otherwise invalid.

What it does: Tells you if your colors pass the readability test.

What the results mean:

  • “FAIL” = People can’t read this 😞

  • “AA” = Most people can read this fine ✅ (This is what you want)

  • “AAA” = Everyone can read this easily ⭐

Examples:

# Normal text
result = cm.wcag_level((100, 100, 100), (255, 255, 255))
print(f"Your colors: {result}")  # "AA", "AAA", or "FAIL"

# Large text (18pt+ or 14pt+ bold) has different requirements
large_result = cm.wcag_level((100, 100, 100), (255, 255, 255), large_text=True)
print(f"Large text level: {large_result}")

Color Difference Functions

For perfectionists who want to know exactly how much colors changed

CMColors.delta_e(color1, color2) float[source]

Compute the Delta E 2000 color difference between two colors.

Accepts color inputs in any supported format (hex, rgb/rgba strings, tuples, named colors, etc.). RGBA inputs will be composited as needed before comparison.

Parameters:
  • color1 – First color (text or sample) in any supported format.

  • color2 – Second color (background or reference) in any supported format.

Returns:

The Delta E 2000 distance. Values below about 2.3 are typically imperceptible to the average observer.

Return type:

float

What it does: Measures how different two colors look to human eyes.

The magic numbers:

  • Under 1.0 = You literally can’t tell the difference

  • 1.0-2.3 = Barely noticeable difference

  • 2.3+ = You can clearly see the difference

Example:

original = (100, 100, 100)
adjusted = (85, 85, 85)

difference = cm.delta_e(original, adjusted)
print(f"Visual difference: {difference:.2f}")
# Lower = more similar looking

Color Format Functions

For working with different color formats

CMColors.parse_to_rgb(color: str) Tuple[int, int, int][source]

Convert a color string in common formats to an RGB triple.

Accepts hex (#RRGGBB, #RGB), functional rgb()/rgba() (alpha composited over white), and CSS color names. Parsing is case-insensitive and will composite RGBA into an opaque RGB when an alpha channel is provided.

Parameters:

color (str) – Color value in hex, rgb(a) function notation, or named color.

Returns:

(R, G, B) with each component as an integer in the range 0–255.

Return type:

tuple

What it does: Converts hex codes, rgb strings, or other formats to RGB tuples.

When to use it: When you have colors in different formats and need them as RGB tuples.

Example:

# Convert hex to RGB
rgb = cm.parse_to_rgb("#7B2DC8")
print(f"RGB: {rgb}")  # (123, 45, 200)

# You can also pass different formats directly to tune_colors
tuned_text, accessible = cm.tune_colors("#7B2DC8", "#FFFFFF")

Color Conversion Functions

For when you need to work with different color systems

CMColors.rgb_to_oklch(rgb: Tuple[int, int, int]) Tuple[float, float, float][source]

Converts an RGB color to the OKLCH color space. OKLCH is a perceptually uniform color space, making it ideal for color manipulation.

Parameters:

rgb (Tuple[int, int, int]) – The RGB tuple (R, G, B).

Returns:

The OKLCH tuple (Lightness, Chroma, Hue).

Lightness is 0-1, Chroma is 0-~0.4, Hue is 0-360.

Return type:

Tuple[float, float, float]

What it does: Converts regular RGB colors to OKLCH (a fancy color system that matches human vision).

Why you might need this: OKLCH is better for making color adjustments that look natural.

What you get: Three numbers - Lightness (0-1), Chroma (0-~0.4), and Hue angle (0-360°).

Example:

rgb = (255, 128, 64)  # Orange color
l, c, h = cm.rgb_to_oklch(rgb)
print(f"Lightness: {l:.2f}, Chroma: {c:.2f}, Hue: {h:.0f}°")

CMColors.oklch_to_rgb(oklch: Tuple[float, float, float]) Tuple[int, int, int][source]

Converts an OKLCH color back to the RGB color space.

Parameters:

oklch (Tuple[float, float, float]) – The OKLCH tuple (Lightness, Chroma, Hue).

Returns:

The RGB tuple (R, G, B).

Return type:

Tuple[int, int, int]

What it does: Converts OKLCH colors back to regular RGB.

When to use it: After you’ve adjusted colors in OKLCH space and need them for CSS.

Example:

# Convert back to RGB for use in your website
oklch_color = (0.7, 0.15, 45.0)
rgb = cm.oklch_to_rgb(oklch_color)
print(f"RGB: {rgb}")  # Ready for CSS!

CMColors.rgb_to_lab(rgb: Tuple[int, int, int]) Tuple[float, float, float][source]

Converts an RGB color to the CIELAB (LAB) color space.

Parameters:

rgb (Tuple[int, int, int]) – RGB components (R, G, B) with values 0–255.

Returns:

LAB tuple (L, a, b) where L is perceptual lightness.

Return type:

Tuple[float, float, float]

What it does: Converts RGB to LAB color space (used in professional color work).

When you need it: Mostly for advanced color calculations or if you’re doing print design.

Example:

rgb = (255, 128, 64)
l_star, a_star, b_star = cm.rgb_to_lab(rgb)
print(f"LAB: L*={l_star:.1f}, a*={a_star:.1f}, b*={b_star:.1f}")

Quick Reference Card

Just want readable colors?

# Simple way
tuned_text, is_accessible = cm.tune_colors(your_text, your_background)

# With details
result = cm.tune_colors(your_text, your_background, details=True)

Want to check colors first?

level = cm.wcag_level(your_text, your_background)
if level == "FAIL":
    tuned_text, _ = cm.tune_colors(your_text, your_background)

Want to see how much changed?

original = (100, 100, 100)
t, _ = cm.tune_colors(original, background)
difference = cm.delta_e(original, tuned_text)
# Under 2.3 = barely noticeable

Working with different color formats?

# Parse any format
rgb = cm.parse_to_rgb("#FF8040")

# Or use directly
tuned_text, _ = cm.tune_colors("#FF8040", "#FFFFFF")

Large text (18pt+ or 14pt+ bold)?

# Large text has relaxed contrast requirements
tuned_text, accessible = cm.tune_colors(text, bg, large_text=True)
level = cm.wcag_level(text, bg, large_text=True)

Function Return Values Quick Guide

tune_colors() returns:

  • details=False (default): (tuned_color_string, is_accessible_boolean)

  • details=True: Dictionary with keys:

    • 'tuned_text' - The tuned color

    • 'status' - True if accessible, False if failed

    • 'wcag_level' - “AA”, “AAA”, or “FAIL”

    • 'improvement_percentage' - How much contrast improved

    • 'message' - Human-readable status message

Other functions return:

  • contrast_ratio() - Float (higher = more readable)

  • wcag_level() - String (“AA”, “AAA”, or “FAIL”)

  • delta_e() - Float (lower = more similar)

  • parse_to_rgb() - RGB tuple (r, g, b)

  • Color conversions - Tuples in respective color spaces