From 51249756fa759d8df534351a08fc19e9720196e2 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Thu, 28 Aug 2025 14:42:24 +0200 Subject: [PATCH 01/17] Add support of device-cmyk() function --- tinycss2/color4.py | 4 ++- tinycss2/color5.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tinycss2/color5.py diff --git a/tinycss2/color4.py b/tinycss2/color4.py index 4c78f1a..8568324 100644 --- a/tinycss2/color4.py +++ b/tinycss2/color4.py @@ -23,8 +23,10 @@ class Color: to [0, 1]. Coordinates can also be set to ``None`` when undefined. """ + COLOR_SPACES = COLOR_SPACES + def __init__(self, space, coordinates, alpha): - assert space in COLOR_SPACES, f"{space} is not a supported color space" + assert space in self.COLOR_SPACES, f"{space} is not a supported color space" self.space = space self.coordinates = tuple( None if coordinate is None else float(coordinate) diff --git a/tinycss2/color5.py b/tinycss2/color5.py new file mode 100644 index 0000000..e3ab5b5 --- /dev/null +++ b/tinycss2/color5.py @@ -0,0 +1,65 @@ +from . import color4 + +COLOR_SPACES = color4.COLOR_SPACES | {'device-cmyk'} +D50 = color4.D50 +D65 = color4.D65 + + +class Color(color4.Color): + COLOR_SPACES = COLOR_SPACES + + +def parse_color(input): + color = color4.parse_color(input) + + if color: + return color + + if isinstance(input, str): + token = parse_one_component_value(input, skip_comments=True) + else: + token = input + + if token.type == 'function': + tokens = [ + token for token in token.arguments + if token.type not in ('whitespace', 'comment')] + name = token.lower_name + length = len(tokens) + + if length in (7, 9) and all(token == ',' for token in tokens[1::2]): + old_syntax = True + tokens = tokens[::2] + elif length == 4: + old_syntax = False + elif length == 6 and tokens[4] == '/': + tokens.pop(4) + old_syntax = False + else: + return + args, alpha = tokens[:4], color4._parse_alpha(tokens[4:]) + + if name == 'device-cmyk': + return _parse_device_cmyk(args, alpha, old_syntax) + + +def _parse_device_cmyk(args, alpha, old_syntax): + """Parse a list of CMYK channels. + + If args is a list of 4 NUMBER or PERCENTAGE tokens, return + device-cmyk :class:`Color`. Otherwise, return None. + + Input C, M, Y, K ranges are [0, 1], output are [0, 1]. + + """ + if old_syntax: + if color4._types(args) != {'number'}: + return + else: + if color4._types(args) <= {'numbers', 'percentage'}: + return + cmyk = [ + arg.value if arg.type == 'number' else + arg.value / 100 if arg.type == 'percentage' else None + for arg in args] + return Color('device-cmyk', cmyk, alpha) From 5b7bae2bff691bdbbf2857e2a324e724dfa71f1e Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Thu, 28 Aug 2025 16:27:15 +0200 Subject: [PATCH 02/17] Fix new syntax of CMYK --- tinycss2/color5.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinycss2/color5.py b/tinycss2/color5.py index e3ab5b5..8b25224 100644 --- a/tinycss2/color5.py +++ b/tinycss2/color5.py @@ -56,7 +56,7 @@ def _parse_device_cmyk(args, alpha, old_syntax): if color4._types(args) != {'number'}: return else: - if color4._types(args) <= {'numbers', 'percentage'}: + if not color4._types(args) <= {'numbers', 'percentage'}: return cmyk = [ arg.value if arg.type == 'number' else From 359f227756b991a5158a627de36b9a5b17c39199 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Thu, 28 Aug 2025 19:32:35 +0200 Subject: [PATCH 03/17] Add support for color profiles --- tinycss2/color4.py | 3 ++- tinycss2/color5.py | 27 +++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tinycss2/color4.py b/tinycss2/color4.py index 8568324..dd4508e 100644 --- a/tinycss2/color4.py +++ b/tinycss2/color4.py @@ -26,7 +26,8 @@ class Color: COLOR_SPACES = COLOR_SPACES def __init__(self, space, coordinates, alpha): - assert space in self.COLOR_SPACES, f"{space} is not a supported color space" + if self.COLOR_SPACES: + assert space in self.COLOR_SPACES, f"{space} is not a supported color space" self.space = space self.coordinates = tuple( None if coordinate is None else float(coordinate) diff --git a/tinycss2/color5.py b/tinycss2/color5.py index 8b25224..b8a4461 100644 --- a/tinycss2/color5.py +++ b/tinycss2/color5.py @@ -6,7 +6,7 @@ class Color(color4.Color): - COLOR_SPACES = COLOR_SPACES + COLOR_SPACES = None def parse_color(input): @@ -25,12 +25,16 @@ def parse_color(input): token for token in token.arguments if token.type not in ('whitespace', 'comment')] name = token.lower_name + + if name == 'color': + space, *tokens = tokens + length = len(tokens) if length in (7, 9) and all(token == ',' for token in tokens[1::2]): old_syntax = True tokens = tokens[::2] - elif length == 4: + elif length in (3, 4): old_syntax = False elif length == 6 and tokens[4] == '/': tokens.pop(4) @@ -41,6 +45,8 @@ def parse_color(input): if name == 'device-cmyk': return _parse_device_cmyk(args, alpha, old_syntax) + elif name == 'color' and not old_syntax: + return _parse_color(space, args, alpha) def _parse_device_cmyk(args, alpha, old_syntax): @@ -63,3 +69,20 @@ def _parse_device_cmyk(args, alpha, old_syntax): arg.value / 100 if arg.type == 'percentage' else None for arg in args] return Color('device-cmyk', cmyk, alpha) + + +def _parse_color(space, args, alpha): + """Parse a color space name list of coordinates. + + Ranges are [0, 1]. + + """ + if not color4._types(args) <= {'number', 'percentage'}: + return + if space.type != 'ident' or not space.value.startswith('--'): + return + coordinates = [ + arg.value if arg.type == 'number' else + arg.value / 100 if arg.type == 'percentage' else None + for arg in args] + return Color(space.value, coordinates, alpha) From e533ccbda81ee0ad40c262bf6324318a5d85b46e Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Wed, 3 Sep 2025 14:04:49 +0200 Subject: [PATCH 04/17] Use color4 parse_one_component_value --- tinycss2/color5.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinycss2/color5.py b/tinycss2/color5.py index b8a4461..3fd9a4e 100644 --- a/tinycss2/color5.py +++ b/tinycss2/color5.py @@ -16,7 +16,7 @@ def parse_color(input): return color if isinstance(input, str): - token = parse_one_component_value(input, skip_comments=True) + token = color4.parse_one_component_value(input, skip_comments=True) else: token = input From a3be4b4dc7cb5b788882e749c7ba1af8bd18439c Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Thu, 4 Sep 2025 15:30:42 +0200 Subject: [PATCH 05/17] Add support for light-dark() --- tinycss2/color5.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tinycss2/color5.py b/tinycss2/color5.py index 3fd9a4e..e914a4c 100644 --- a/tinycss2/color5.py +++ b/tinycss2/color5.py @@ -1,6 +1,7 @@ from . import color4 COLOR_SPACES = color4.COLOR_SPACES | {'device-cmyk'} +COLOR_SCHEMES = {'light', 'dark'} D50 = color4.D50 D65 = color4.D65 @@ -9,12 +10,21 @@ class Color(color4.Color): COLOR_SPACES = None -def parse_color(input): +def parse_color(input, color_schemes=None): color = color4.parse_color(input) if color: return color + if color_schemes is None or color_schemes == 'normal': + color_scheme = 'light' + else: + for color_scheme in color_schemes: + if color_scheme in COLOR_SCHEMES: + break + else: + color_scheme = 'light' + if isinstance(input, str): token = color4.parse_one_component_value(input, skip_comments=True) else: @@ -45,6 +55,8 @@ def parse_color(input): if name == 'device-cmyk': return _parse_device_cmyk(args, alpha, old_syntax) + elif name == 'light-dark': + return _parse_light_dark(args, color_scheme) elif name == 'color' and not old_syntax: return _parse_color(space, args, alpha) @@ -71,6 +83,19 @@ def _parse_device_cmyk(args, alpha, old_syntax): return Color('device-cmyk', cmyk, alpha) +def _parse_light_dark(args, color_scheme): + colors = [] + for arg in args: + if color := parse_color(arg, color_scheme): + colors.append(color) + if len(colors) == 2: + if color_scheme == 'light': + return colors[0] + else: + return colors[1] + return + + def _parse_color(space, args, alpha): """Parse a color space name list of coordinates. From 2d6a1961f4fc8ab426aa306b240975c731746623 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Mon, 8 Sep 2025 19:25:24 +0200 Subject: [PATCH 06/17] Deals with old / new syntax --- tinycss2/color5.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tinycss2/color5.py b/tinycss2/color5.py index e914a4c..805fe83 100644 --- a/tinycss2/color5.py +++ b/tinycss2/color5.py @@ -35,30 +35,31 @@ def parse_color(input, color_schemes=None): token for token in token.arguments if token.type not in ('whitespace', 'comment')] name = token.lower_name + alpha = [] if name == 'color': space, *tokens = tokens length = len(tokens) - if length in (7, 9) and all(token == ',' for token in tokens[1::2]): - old_syntax = True + old_syntax = all(token == ',' for token in tokens[1::2]) + if old_syntax: tokens = tokens[::2] - elif length in (3, 4): - old_syntax = False - elif length == 6 and tokens[4] == '/': - tokens.pop(4) - old_syntax = False else: - return - args, alpha = tokens[:4], color4._parse_alpha(tokens[4:]) + for index, token in enumerate(tokens): + if token == '/': + alpha = tokens[index + 1:] + tokens = tokens[:index] + break if name == 'device-cmyk': - return _parse_device_cmyk(args, alpha, old_syntax) + return _parse_device_cmyk(tokens, color4._parse_alpha(alpha), old_syntax) + elif name == 'color': + return _parse_color(space, tokens, color4._parse_alpha(alpha)) elif name == 'light-dark': - return _parse_light_dark(args, color_scheme) - elif name == 'color' and not old_syntax: - return _parse_color(space, args, alpha) + return _parse_light_dark(tokens, color_scheme) + else: + return def _parse_device_cmyk(args, alpha, old_syntax): @@ -74,7 +75,7 @@ def _parse_device_cmyk(args, alpha, old_syntax): if color4._types(args) != {'number'}: return else: - if not color4._types(args) <= {'numbers', 'percentage'}: + if not color4._types(args) <= {'number', 'percentage'}: return cmyk = [ arg.value if arg.type == 'number' else From 52cd9b559cec09b00fb347ae605d423f83653853 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Mon, 8 Sep 2025 19:32:31 +0200 Subject: [PATCH 07/17] Remove useless variable --- tinycss2/color5.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tinycss2/color5.py b/tinycss2/color5.py index 805fe83..7592459 100644 --- a/tinycss2/color5.py +++ b/tinycss2/color5.py @@ -40,8 +40,6 @@ def parse_color(input, color_schemes=None): if name == 'color': space, *tokens = tokens - length = len(tokens) - old_syntax = all(token == ',' for token in tokens[1::2]) if old_syntax: tokens = tokens[::2] From 325000b1fbbe5b13e493c2e933ca9d688fbbea53 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Mon, 15 Sep 2025 18:17:32 +0200 Subject: [PATCH 08/17] Manage channels greater or lower than 100% or 0% --- tinycss2/color5.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tinycss2/color5.py b/tinycss2/color5.py index 7592459..01a7f84 100644 --- a/tinycss2/color5.py +++ b/tinycss2/color5.py @@ -79,6 +79,7 @@ def _parse_device_cmyk(args, alpha, old_syntax): arg.value if arg.type == 'number' else arg.value / 100 if arg.type == 'percentage' else None for arg in args] + cmyk = [max(0., min(1., float(channel))) for channel in cmyk] return Color('device-cmyk', cmyk, alpha) From 042781d92ee534f7268cd50e8bd07e22fb03acf6 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Mon, 15 Sep 2025 18:21:27 +0200 Subject: [PATCH 09/17] Accept cmyk colors with 4 channels only --- tinycss2/color5.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tinycss2/color5.py b/tinycss2/color5.py index 01a7f84..823fba5 100644 --- a/tinycss2/color5.py +++ b/tinycss2/color5.py @@ -75,6 +75,8 @@ def _parse_device_cmyk(args, alpha, old_syntax): else: if not color4._types(args) <= {'number', 'percentage'}: return + if len(args) != 4: + return cmyk = [ arg.value if arg.type == 'number' else arg.value / 100 if arg.type == 'percentage' else None From 431f2f9d57b51bd8cf386590fe793fceffb22a0f Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Mon, 15 Sep 2025 21:39:45 +0200 Subject: [PATCH 10/17] Add tests for Color 5 --- tests/test_tinycss2.py | 177 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 3 deletions(-) diff --git a/tests/test_tinycss2.py b/tests/test_tinycss2.py index 0df3582..090ce73 100644 --- a/tests/test_tinycss2.py +++ b/tests/test_tinycss2.py @@ -20,6 +20,8 @@ from tinycss2.color3 import parse_color as parse_color3 # isort:skip from tinycss2.color4 import Color # isort:skip from tinycss2.color4 import parse_color as parse_color4 # isort:skip +from tinycss2.color5 import Color # isort:skip +from tinycss2.color5 import parse_color as parse_color5 # isort:skip from tinycss2.nth import parse_nth # isort:skip @@ -169,6 +171,11 @@ def test_color_currentcolor_4(): assert parse_color4(value) == 'currentcolor' +def test_color_currentcolor_5(): + for value in ('currentcolor', 'currentColor', 'CURRENTCOLOR'): + assert parse_color5(value) == 'currentcolor' + + @json_test() def test_color_function_4(input): if not (color := parse_color4(input)): @@ -183,6 +190,34 @@ def test_color_function_4(input): return result +@json_test(filename='color_function_4.json') +def test_color_function_4_with_5(input): + if not (color := parse_color5(input)): + return None + (*coordinates, alpha) = color + result = f'color({color.space}' + for coordinate in coordinates: + result += f' {_number(coordinate)}' + if alpha != 1: + result += f' / {_number(alpha)}' + result += ')' + return result + + +@json_test() +def test_color_functions_5(input): + if not (color := parse_color5(input)): + return None + (*coordinates, alpha) = color + result = f'color({color.space}' + for coordinate in coordinates: + result += f' {_number(coordinate)}' + if alpha != 1: + result += f' / {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_hexadecimal_3(input): if not (color := parse_color3(input)): @@ -210,9 +245,23 @@ def test_color_hexadecimal_4(input): return result +@json_test(filename='color_hexadecimal_4.json') +def test_color_hexadecimal_4_with_5(input): + if not (color := parse_color5(input)): + return None + assert color.space == 'srgb' + (*coordinates, alpha) = color + result = f'rgb{"a" if alpha != 1 else ""}(' + result += f'{", ".join(_number(coordinate * 255) for coordinate in coordinates)}' + if alpha != 1: + result += f', {_number(alpha)}' + result += ')' + return result + + @json_test(filename='color_hexadecimal_3.json') -def test_color_hexadecimal_3_with_4(input): - if not (color := parse_color4(input)): +def test_color_hexadecimal_3_with_5(input): + if not (color := parse_color5(input)): return None assert color.space == 'srgb' (*coordinates, alpha) = color @@ -251,6 +300,20 @@ def test_color_hsl_3_with_4(input): return result +@json_test(filename='color_hsl_3.json') +def test_color_hsl_3_with_5(input): + if not (color := parse_color5(input)): + return None + assert color.space == 'hsl' + (*coordinates, alpha) = color.to('srgb') + result = f'rgb{"a" if alpha != 1 else ""}(' + result += f'{", ".join(_number(coordinate * 255) for coordinate in coordinates)}' + if alpha != 1: + result += f', {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_hsl_4(input): if not (color := parse_color4(input)): @@ -265,6 +328,20 @@ def test_color_hsl_4(input): return result +@json_test(filename='color_hsl_4.json') +def test_color_hsl_4_with_5(input): + if not (color := parse_color5(input)): + return None + assert color.space == 'hsl' + (*coordinates, alpha) = color.to('srgb') + result = f'rgb{"a" if alpha != 1 else ""}(' + result += f'{", ".join(_number(coordinate * 255) for coordinate in coordinates)}' + if alpha != 1: + result += f', {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_hwb_4(input): if not (color := parse_color4(input)): @@ -279,6 +356,20 @@ def test_color_hwb_4(input): return result +@json_test(filename='color_hwb_4.json') +def test_color_hwb_4_with_5(input): + if not (color := parse_color5(input)): + return None + assert color.space == 'hwb' + (*coordinates, alpha) = color.to('srgb') + result = f'rgb{"a" if alpha != 1 else ""}(' + result += f'{", ".join(_number(coordinate * 255) for coordinate in coordinates)}' + if alpha != 1: + result += f', {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_keywords_3(input): if not (color := parse_color3(input)): @@ -310,6 +401,22 @@ def test_color_keywords_3_with_4(input): return result +@json_test(filename='color_keywords_3.json') +def test_color_keywords_3_with_5(input): + if not (color := parse_color5(input)): + return None + elif isinstance(color, str): + return color + assert color.space == 'srgb' + (*coordinates, alpha) = color + result = f'rgb{"a" if alpha != 1 else ""}(' + result += f'{", ".join(_number(coordinate * 255) for coordinate in coordinates)}' + if alpha != 1: + result += f', {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_keywords_4(input): if not (color := parse_color4(input)): @@ -326,6 +433,22 @@ def test_color_keywords_4(input): return result +@json_test(filename='color_keywords_4.json') +def test_color_keywords_4_with_5(input): + if not (color := parse_color5(input)): + return None + elif isinstance(color, str): + return color + assert color.space == 'srgb' + (*coordinates, alpha) = color + result = f'rgb{"a" if alpha != 1 else ""}(' + result += f'{", ".join(_number(coordinate * 255) for coordinate in coordinates)}' + if alpha != 1: + result += f', {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_lab_4(input): if not (color := parse_color4(input)): @@ -342,6 +465,22 @@ def test_color_lab_4(input): return result +@json_test(filename='color_lab_4.json') +def test_color_lab_4_with_5(input): + if not (color := parse_color5(input)): + return None + elif isinstance(color, str): + return color + assert color.space == 'lab' + (*coordinates, alpha) = color + result = f'{color.space}(' + result += f'{" ".join(_number(coordinate) for coordinate in coordinates)}' + if alpha != 1: + result += f' / {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_oklab_4(input): if not (color := parse_color4(input)): @@ -358,6 +497,22 @@ def test_color_oklab_4(input): return result +@json_test(filename='color_oklab_4.json') +def test_color_oklab_4_with_5(input): + if not (color := parse_color5(input)): + return None + elif isinstance(color, str): + return color + assert color.space == 'oklab' + (*coordinates, alpha) = color + result = f'{color.space}(' + result += f'{" ".join(_number(coordinate) for coordinate in coordinates)}' + if alpha != 1: + result += f' / {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_lch_4(input): if not (color := parse_color4(input)): @@ -375,11 +530,27 @@ def test_color_lch_4(input): @json_test() -def test_color_oklch_4(input): +def test_color_lch_4(input): if not (color := parse_color4(input)): return None elif isinstance(color, str): return color + assert color.space == 'lch' + (*coordinates, alpha) = color + result = f'{color.space}(' + result += f'{" ".join(_number(coordinate) for coordinate in coordinates)}' + if alpha != 1: + result += f' / {_number(alpha)}' + result += ')' + return result + + +@json_test(filename='color_oklch_4.json') +def test_color_oklch_4_with_5(input): + if not (color := parse_color5(input)): + return None + elif isinstance(color, str): + return color assert color.space == 'oklch' (*coordinates, alpha) = color result = f'{color.space}(' From f0079bd5e1970d6d83a7cb76ed7aafcb8691eb92 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Tue, 16 Sep 2025 17:16:01 +0200 Subject: [PATCH 11/17] Add tests for Color 5 --- tests/test_tinycss2.py | 50 +++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/tests/test_tinycss2.py b/tests/test_tinycss2.py index 090ce73..bfe23a4 100644 --- a/tests/test_tinycss2.py +++ b/tests/test_tinycss2.py @@ -161,6 +161,17 @@ def _number(value): return str(int(value) if value.is_integer() else value) +def _build_color(color): + (*coordinates, alpha) = color + result = f'color({color.space}' + for coordinate in coordinates: + result += f' {_number(coordinate)}' + if alpha != 1: + result += f' / {_number(alpha)}' + result += ')' + return result + + def test_color_currentcolor_3(): for value in ('currentcolor', 'currentColor', 'CURRENTCOLOR'): assert parse_color3(value) == 'currentColor' @@ -181,13 +192,7 @@ def test_color_function_4(input): if not (color := parse_color4(input)): return None (*coordinates, alpha) = color - result = f'color({color.space}' - for coordinate in coordinates: - result += f' {_number(coordinate)}' - if alpha != 1: - result += f' / {_number(alpha)}' - result += ')' - return result + return _build_color(color) @json_test(filename='color_function_4.json') @@ -195,26 +200,25 @@ def test_color_function_4_with_5(input): if not (color := parse_color5(input)): return None (*coordinates, alpha) = color - result = f'color({color.space}' - for coordinate in coordinates: - result += f' {_number(coordinate)}' - if alpha != 1: - result += f' / {_number(alpha)}' - result += ')' - return result + return _build_color(color) @json_test() def test_color_functions_5(input): - if not (color := parse_color5(input)): - return None - (*coordinates, alpha) = color - result = f'color({color.space}' - for coordinate in coordinates: - result += f' {_number(coordinate)}' - if alpha != 1: - result += f' / {_number(alpha)}' - result += ')' + if input.startswith('light-dark'): + result = [] + if not (light_color := parse_color5(input, ('light',))): + result.append(None) + else: + result.append(_build_color(light_color)) + if not (dark_color := parse_color5(input, ('dark',))): + result.append(None) + else: + result.append(_build_color(dark_color)) + else: + if not (color := parse_color5(input)): + return None + result = _build_color(color) return result From 419d9a51e555bdb350fc13c11445f6545c2ea52d Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Tue, 16 Sep 2025 17:18:04 +0200 Subject: [PATCH 12/17] Test lch colors with Color 5 --- tests/test_tinycss2.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_tinycss2.py b/tests/test_tinycss2.py index bfe23a4..7310bc9 100644 --- a/tests/test_tinycss2.py +++ b/tests/test_tinycss2.py @@ -20,7 +20,6 @@ from tinycss2.color3 import parse_color as parse_color3 # isort:skip from tinycss2.color4 import Color # isort:skip from tinycss2.color4 import parse_color as parse_color4 # isort:skip -from tinycss2.color5 import Color # isort:skip from tinycss2.color5 import parse_color as parse_color5 # isort:skip from tinycss2.nth import parse_nth # isort:skip @@ -533,9 +532,9 @@ def test_color_lch_4(input): return result -@json_test() -def test_color_lch_4(input): - if not (color := parse_color4(input)): +@json_test(filename='color_lch_4.json') +def test_color_lch_4_with_5(input): + if not (color := parse_color5(input)): return None elif isinstance(color, str): return color From cbad1c83a5e6d4230ac40a491aed91b52c68e044 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Tue, 16 Sep 2025 17:37:34 +0200 Subject: [PATCH 13/17] Update submodule to point on color 5 branch --- tests/css-parsing-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/css-parsing-tests b/tests/css-parsing-tests index 530ab15..88fc3fc 160000 --- a/tests/css-parsing-tests +++ b/tests/css-parsing-tests @@ -1 +1 @@ -Subproject commit 530ab150796b959240fb09eae3b764d8bae6d182 +Subproject commit 88fc3fc33986f835b6658b1b824b50c9550723f8 From 4247cb73ced9513358f61b03aa5d4040a5e2d3b8 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Tue, 16 Sep 2025 17:40:52 +0200 Subject: [PATCH 14/17] Remove unused variables --- tests/test_tinycss2.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_tinycss2.py b/tests/test_tinycss2.py index 7310bc9..d8419b0 100644 --- a/tests/test_tinycss2.py +++ b/tests/test_tinycss2.py @@ -190,7 +190,6 @@ def test_color_currentcolor_5(): def test_color_function_4(input): if not (color := parse_color4(input)): return None - (*coordinates, alpha) = color return _build_color(color) @@ -198,7 +197,6 @@ def test_color_function_4(input): def test_color_function_4_with_5(input): if not (color := parse_color5(input)): return None - (*coordinates, alpha) = color return _build_color(color) From 1e47dd105e135537b7196f5f7f5d68ae6b4d062f Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Thu, 18 Sep 2025 17:37:05 +0200 Subject: [PATCH 15/17] Manage None color in _build_color --- tests/test_tinycss2.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/tests/test_tinycss2.py b/tests/test_tinycss2.py index d8419b0..480e8a6 100644 --- a/tests/test_tinycss2.py +++ b/tests/test_tinycss2.py @@ -161,6 +161,8 @@ def _number(value): def _build_color(color): + if color is None: + return (*coordinates, alpha) = color result = f'color({color.space}' for coordinate in coordinates: @@ -188,30 +190,20 @@ def test_color_currentcolor_5(): @json_test() def test_color_function_4(input): - if not (color := parse_color4(input)): - return None - return _build_color(color) + return _build_color(parse_color4(input)) @json_test(filename='color_function_4.json') def test_color_function_4_with_5(input): - if not (color := parse_color5(input)): - return None - return _build_color(color) + return _build_color(parse_color5(input)) @json_test() def test_color_functions_5(input): if input.startswith('light-dark'): result = [] - if not (light_color := parse_color5(input, ('light',))): - result.append(None) - else: - result.append(_build_color(light_color)) - if not (dark_color := parse_color5(input, ('dark',))): - result.append(None) - else: - result.append(_build_color(dark_color)) + result.append(_build_color(parse_color5(input, ('light',)))) + result.append(_build_color(parse_color5(input, ('dark',)))) else: if not (color := parse_color5(input)): return None From c3f7a926e369a0b4f1979921549419b4c434bbc9 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Thu, 18 Sep 2025 17:40:05 +0200 Subject: [PATCH 16/17] Readd removed tests (oopsi) --- tests/test_tinycss2.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/test_tinycss2.py b/tests/test_tinycss2.py index 480e8a6..87bf894 100644 --- a/tests/test_tinycss2.py +++ b/tests/test_tinycss2.py @@ -224,6 +224,19 @@ def test_color_hexadecimal_3(input): return result +@json_test(filename='color_hexadecimal_3.json') +def test_color_hexadecimal_3_with_4(input): + if not (color := parse_color4(input)): + return None + (*coordinates, alpha) = color + result = f'rgb{"a" if alpha != 1 else ""}(' + result += f'{", ".join(_number(coordinate * 255) for coordinate in coordinates)}' + if alpha != 1: + result += f', {_number(alpha)}' + result += ')' + return result + + @json_test() def test_color_hexadecimal_4(input): if not (color := parse_color4(input)): @@ -538,6 +551,22 @@ def test_color_lch_4_with_5(input): return result +@json_test() +def test_color_oklch_4(input): + if not (color := parse_color4(input)): + return None + elif isinstance(color, str): + return color + assert color.space == 'oklch' + (*coordinates, alpha) = color + result = f'{color.space}(' + result += f'{" ".join(_number(coordinate) for coordinate in coordinates)}' + if alpha != 1: + result += f' / {_number(alpha)}' + result += ')' + return result + + @json_test(filename='color_oklch_4.json') def test_color_oklch_4_with_5(input): if not (color := parse_color5(input)): From 725d2b5efc49b2b8c5627583769b5bbd16b3c780 Mon Sep 17 00:00:00 2001 From: Lucie Anglade Date: Thu, 18 Sep 2025 17:45:53 +0200 Subject: [PATCH 17/17] Simplify test_color_functions_5 --- tests/test_tinycss2.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_tinycss2.py b/tests/test_tinycss2.py index 87bf894..4580062 100644 --- a/tests/test_tinycss2.py +++ b/tests/test_tinycss2.py @@ -205,9 +205,7 @@ def test_color_functions_5(input): result.append(_build_color(parse_color5(input, ('light',)))) result.append(_build_color(parse_color5(input, ('dark',)))) else: - if not (color := parse_color5(input)): - return None - result = _build_color(color) + result = _build_color(parse_color5(input)) return result