-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #141 from jakob-bagterp/feature/add-hex-class-for-…
…custom-text-color Feature: Add hex classes ColorHex and BgColorHex for custom text color
- Loading branch information
Showing
10 changed files
with
253 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Copyright 2022 – present, Jakob Bagterp. BSD 3-Clause license and refer to LICENSE file. | ||
|
||
from abc import ABC, abstractmethod | ||
|
||
from ... import helper | ||
from ...constants.ansi import RESET_ALL | ||
from ...helper.error import message_for_hex_value_error | ||
from ...helper.validate import is_valid_hex_value | ||
from ..foreground.rgb import ColorRGB | ||
from .rgb import RGB_ABC | ||
|
||
|
||
class Hex_ABC(ABC): | ||
"""Abstract base class for custom hex color instances.""" | ||
|
||
OFF = RESET_ALL | ||
|
||
__slots__ = ["hex", "_rgb", "_ansi_code"] | ||
|
||
def __init__(self, hex: str) -> None: | ||
if not is_valid_hex_value(hex): | ||
raise ValueError(message_for_hex_value_error(hex)) | ||
|
||
self.hex: str = hex.lower() | ||
|
||
self._rgb: RGB_ABC = self.convert_hex_to_rgb() | ||
self._ansi_code: str = self.generate_ansi_code() | ||
|
||
def __str__(self) -> str: | ||
return self._ansi_code | ||
|
||
def __repr__(self) -> str: | ||
return f"Hex: #{self.hex.lstrip('#')}" | ||
|
||
def convert_hex_to_rgb(self) -> RGB_ABC: | ||
"""Method to convert hex to RGB color.""" | ||
|
||
red, green, blue = helper.convert.hex_to_rgb(self.hex) | ||
return ColorRGB(red, green, blue) | ||
|
||
@abstractmethod | ||
def generate_ansi_code(self) -> str: | ||
"""Method to generate ANSI RGB color sequence.""" | ||
|
||
raise NotImplementedError # pragma: no cover |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Copyright 2022 – present, Jakob Bagterp. BSD 3-Clause license and refer to LICENSE file. | ||
|
||
from ... import helper | ||
from ...constants.ansi import AnsiRgbColorSelector | ||
from ..abc.hex import Hex_ABC | ||
|
||
|
||
class BgColorHex(Hex_ABC): | ||
"""Class for custom background color defined as hex color.""" | ||
|
||
def generate_ansi_code(self) -> str: | ||
return helper.generate.ansi_rgb_color_sequence(AnsiRgbColorSelector.BACKGROUND, self._rgb) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Copyright 2022 – present, Jakob Bagterp. BSD 3-Clause license and refer to LICENSE file. | ||
|
||
from ... import helper | ||
from ...constants.ansi import AnsiRgbColorSelector | ||
from ..abc.hex import Hex_ABC | ||
|
||
|
||
class ColorHex(Hex_ABC): | ||
"""Class for custom foreground text color defined as hex color.""" | ||
|
||
def generate_ansi_code(self) -> str: | ||
return helper.generate.ansi_rgb_color_sequence(AnsiRgbColorSelector.FOREGROUND, self._rgb) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Copyright 2022 – present, Jakob Bagterp. BSD 3-Clause license and refer to LICENSE file. | ||
|
||
import pytest | ||
import terminal | ||
|
||
from colorist import BgColorHex | ||
|
||
BLACK_MOCK_TEXT = "Only color this \033[48;2;0;0;0mword\033[0m.\n" | ||
|
||
WHITE_MOCK_TEXT = "Only color this \033[48;2;255;255;255mword\033[0m.\n" | ||
|
||
|
||
@pytest.mark.parametrize("hex, expected", [ | ||
("#000", BLACK_MOCK_TEXT), | ||
("#000000", BLACK_MOCK_TEXT), | ||
("000", BLACK_MOCK_TEXT), | ||
("000000", BLACK_MOCK_TEXT), | ||
("#fFf", WHITE_MOCK_TEXT), | ||
("#fFFFFf", WHITE_MOCK_TEXT), | ||
("fFf", WHITE_MOCK_TEXT), | ||
("fFFFFf", WHITE_MOCK_TEXT), | ||
("aB3", "Only color this \033[48;2;170;187;51mword\033[0m.\n"), | ||
("#9b9Ac7", "Only color this \033[48;2;155;154;199mword\033[0m.\n"), | ||
]) | ||
def test_custom_text_background_hex_color_f_string(hex: str, expected: str, capfd: object) -> None: | ||
bg_color_hex = BgColorHex(hex) | ||
print(f"Only color this {bg_color_hex}word{BgColorHex.OFF}.") | ||
terminal_output = terminal.get_output(capfd) | ||
assert terminal_output == expected |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Copyright 2022 – present, Jakob Bagterp. BSD 3-Clause license and refer to LICENSE file. | ||
|
||
import pytest | ||
import terminal | ||
|
||
from colorist import ColorHex | ||
|
||
BLACK_MOCK_TEXT = "Only color this \033[38;2;0;0;0mword\033[0m.\n" | ||
|
||
WHITE_MOCK_TEXT = "Only color this \033[38;2;255;255;255mword\033[0m.\n" | ||
|
||
|
||
@pytest.mark.parametrize("hex, expected", [ | ||
("#000", BLACK_MOCK_TEXT), | ||
("#000000", BLACK_MOCK_TEXT), | ||
("000", BLACK_MOCK_TEXT), | ||
("000000", BLACK_MOCK_TEXT), | ||
("#fFf", WHITE_MOCK_TEXT), | ||
("#fFFFFf", WHITE_MOCK_TEXT), | ||
("fFf", WHITE_MOCK_TEXT), | ||
("fFFFFf", WHITE_MOCK_TEXT), | ||
("aB3", "Only color this \033[38;2;170;187;51mword\033[0m.\n"), | ||
("#9b9Ac7", "Only color this \033[38;2;155;154;199mword\033[0m.\n"), | ||
]) | ||
def test_custom_text_hex_color_f_string(hex: str, expected: str, capfd: object) -> None: | ||
color_hex = ColorHex(hex) | ||
print(f"Only color this {color_hex}word{ColorHex.OFF}.") | ||
terminal_output = terminal.get_output(capfd) | ||
assert terminal_output == expected |
33 changes: 33 additions & 0 deletions
33
test/helper/convert/convert_hex_to_rgb_exception_handling_test.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Copyright 2022 – present, Jakob Bagterp. BSD 3-Clause license and refer to LICENSE file. | ||
|
||
from contextlib import nullcontext as does_not_raise | ||
from typing import Any | ||
|
||
import pytest | ||
|
||
from colorist import helper | ||
|
||
|
||
@pytest.mark.parametrize("hex, expectation", [ | ||
("#1AFFa1", does_not_raise()), | ||
("1AFFa1", does_not_raise()), | ||
("#1AF", does_not_raise()), | ||
("1AF", does_not_raise()), | ||
("#000000", does_not_raise()), | ||
("000000", does_not_raise()), | ||
("#000", does_not_raise()), | ||
("000", does_not_raise()), | ||
("#FfFFFF", does_not_raise()), | ||
("FFfFFF", does_not_raise()), | ||
("#ffF", does_not_raise()), | ||
("Fff", does_not_raise()), | ||
("#1AFFa10", pytest.raises(ValueError)), | ||
("1AFFa10", pytest.raises(ValueError)), | ||
("#1A", pytest.raises(ValueError)), | ||
("1A", pytest.raises(ValueError)), | ||
("#random", pytest.raises(ValueError)), | ||
("random", pytest.raises(ValueError)), | ||
]) | ||
def test_exception_handling_of_convert_hex_to_rgb(hex: str, expectation: Any) -> None: | ||
with expectation: | ||
_ = helper.convert.hex_to_rgb(hex) is not None |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Copyright 2022 – present, Jakob Bagterp. BSD 3-Clause license and refer to LICENSE file. | ||
|
||
from contextlib import nullcontext as does_not_raise | ||
from typing import Any | ||
|
||
import pytest | ||
|
||
from colorist import BgColorHex, ColorHex | ||
|
||
MOCK_DATASET = [ | ||
("#1AFFa1", does_not_raise()), | ||
("1AFFa1", does_not_raise()), | ||
("#1AF", does_not_raise()), | ||
("1AF", does_not_raise()), | ||
("#000000", does_not_raise()), | ||
("000000", does_not_raise()), | ||
("#000", does_not_raise()), | ||
("000", does_not_raise()), | ||
("#FfFFFF", does_not_raise()), | ||
("FFfFFF", does_not_raise()), | ||
("#ffF", does_not_raise()), | ||
("Fff", does_not_raise()), | ||
("#1AFFa10", pytest.raises(ValueError)), | ||
("1AFFa10", pytest.raises(ValueError)), | ||
("#1A", pytest.raises(ValueError)), | ||
("1A", pytest.raises(ValueError)), | ||
("#random", pytest.raises(ValueError)), | ||
("random", pytest.raises(ValueError)), | ||
] | ||
|
||
|
||
@pytest.mark.parametrize("hex, expectation", MOCK_DATASET) | ||
def test_exception_handling_of_color_hex(hex: str, expectation: Any) -> None: | ||
with expectation: | ||
_ = ColorHex(hex) is not None | ||
|
||
|
||
@pytest.mark.parametrize("hex, expectation", MOCK_DATASET) | ||
def test_exception_handling_of_background_color_hex(hex: str, expectation: Any) -> None: | ||
with expectation: | ||
_ = BgColorHex(hex) is not None |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Copyright 2022 – present, Jakob Bagterp. BSD 3-Clause license and refer to LICENSE file. | ||
|
||
import pytest | ||
|
||
from colorist import BgColorHex, ColorHex | ||
|
||
MOCK_DATASET = [ | ||
("#000", "Hex: #000"), | ||
("#000000", "Hex: #000000"), | ||
("000", "Hex: #000"), | ||
("000000", "Hex: #000000"), | ||
("#fFf", "Hex: #fff"), | ||
("#fFFFFf", "Hex: #ffffff"), | ||
("fFf", "Hex: #fff"), | ||
("fFFFFf", "Hex: #ffffff"), | ||
("aB3", "Hex: #ab3"), | ||
("#9b9Ac7", "Hex: #9b9ac7"), | ||
] | ||
|
||
|
||
@pytest.mark.parametrize("hex, expected_repr", MOCK_DATASET) | ||
def test_repr_of_color_hex(hex: str, expected_repr: str) -> None: | ||
color_hex = ColorHex(hex) | ||
assert repr(color_hex) == expected_repr | ||
|
||
|
||
@pytest.mark.parametrize("hex, expected_repr", MOCK_DATASET) | ||
def test_repr_of_background_color_hex(hex: str, expected_repr: str) -> None: | ||
color_hex = BgColorHex(hex) | ||
assert repr(color_hex) == expected_repr |