aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Touhey <thomas@touhey.fr>2022-01-01 12:53:02 +0100
committerThomas Touhey <thomas@touhey.fr>2022-01-01 12:53:02 +0100
commit56adca4f8f7ca27f9549f6e2ecdbf4191e35af4b (patch)
treec4437af466f49b155105eb4741361a3069640a73
parent246036d0133f8e75562d2ded973a1c937c2faa52 (diff)
Fixed the documentation a tad, made extended hex support optional
-rw-r--r--LICENSE.txt2
-rw-r--r--README.rst26
-rwxr-xr-xtests/test_colors.py2
-rwxr-xr-xtests/test_decoders.py1
-rw-r--r--thcolor/builtin.py16
-rw-r--r--thcolor/colors.py24
-rw-r--r--thcolor/decoders.py29
-rw-r--r--thcolor/utils.py16
8 files changed, 85 insertions, 31 deletions
diff --git a/LICENSE.txt b/LICENSE.txt
index d1defab..bbb3793 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (C) 2018-2019 Thomas Touhey <thomas@touhey.fr>
+Copyright (C) 2018-2022 Thomas Touhey <thomas@touhey.fr>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
diff --git a/README.rst b/README.rst
index 759e796..0ced2f7 100644
--- a/README.rst
+++ b/README.rst
@@ -17,40 +17,40 @@ Converting an RGB color to HSL:
.. code-block:: python
- from thcolor import Color
+ from thcolor.colors import SRGBColor
- color = Color(Color.Type.RGB, 55, 23, 224)
- print(color.hsl())
+ color = SRGBColor.frombytes(55, 23, 224)
+ print(color.ashsl())
Converting a HSL color to RGB with an alpha value:
.. code-block:: python
- from thcolor import Color, Angle
+ from thcolor.colors import HSLColor
+ from thcolor.angles import DegreesAngle
- alpha = 0.75
- color = Color(Color.Type.HSL, Angle(Angle.Type.DEG, 180), 0.5, 1.0, alpha)
- print(color.rgba())
+ color = HSLColor(DegreesAngle(180), 0.5, 1.0, 0.75)
+ print(color.assrgb())
Converting a textual representation to the RGBA color components:
.. code-block:: python
- from thcolor import Color
+ from thcolor.colors import Color
- color = Color.from_text("darker(10%, hsl(0, 1, 50.0%))")
- print(color.rgba())
+ color = Color.fromtext('darker(10%, hsl(0, 1, 50.0%))')
+ print(color.assrgb())
Getting the CSS color representations (with compatibility for earlier CSS
versions) from a textual representation:
.. code-block:: python
- from thcolor import Color
+ from thcolor.colors import Color
- color = Color.from_text("gray(red( #123456 )/0.2/)")
+ color = Color.fromtext('gray(red( #123456 )/0.2/)')
for repres in color.css():
- print(f"color: {repres}")
+ print(f'color: {repres}')
.. _Thomas Touhey: https://thomas.touhey.fr/
.. _textoutpc: https://textout.touhey.pro/
diff --git a/tests/test_colors.py b/tests/test_colors.py
index 58988a5..eb6d07a 100755
--- a/tests/test_colors.py
+++ b/tests/test_colors.py
@@ -33,6 +33,6 @@ from thcolor.colors import SRGBColor, HSLColor, HWBColor
)),
))
def test_css(color, expected):
- assert color.css() == expected
+ assert tuple(color.css()) == expected
# End of file.
diff --git a/tests/test_decoders.py b/tests/test_decoders.py
index 9cf120f..9a15d46 100755
--- a/tests/test_decoders.py
+++ b/tests/test_decoders.py
@@ -228,6 +228,7 @@ class TestDefaultDecoder:
@pytest.mark.parametrize('test_input,expected', (
('blue', SRGBColor.frombytes(0, 0, 255, 1.00)),
+ ('rgb(110%, 0%, 0%)', SRGBColor(1.0, 0, 0, 1.00)),
('rgb(1, 22,242)', SRGBColor.frombytes(1, 22, 242, 1.00)),
(' rgb (1,22, 242 , 50.0% )', SRGBColor.frombytes(1, 22, 242, 0.50)),
(' rgb (1 22/ 242,50.0%,/)', SRGBColor.frombytes(1, 22, 242, 0.50)),
diff --git a/thcolor/builtin.py b/thcolor/builtin.py
index 077cf09..5cf1646 100644
--- a/thcolor/builtin.py
+++ b/thcolor/builtin.py
@@ -63,9 +63,9 @@ class CSS1ColorDecoder(_MetaColorDecoder):
""" Make an RGB color out of the given components. """
return _SRGBColor(
- red=red / 255,
- green=green / 255,
- blue=blue / 255,
+ red=_factor(red, max_=255, clip=True),
+ green=_factor(green, max_=255, clip=True),
+ blue=_factor(blue, max_=255, clip=True),
alpha=1.0,
)
@@ -225,10 +225,10 @@ class CSS3ColorDecoder(CSS2ColorDecoder):
""" Make an RGB color out of the given components. """
return _SRGBColor(
- red=_factor(red, max_=255),
- green=_factor(green, max_=255),
- blue=_factor(blue, max_=255),
- alpha=_factor(alpha),
+ red=_factor(red, max_=255, clip=True),
+ green=_factor(green, max_=255, clip=True),
+ blue=_factor(blue, max_=255, clip=True),
+ alpha=_factor(alpha, clip=True),
)
def hsl(
@@ -256,6 +256,8 @@ class CSS4ColorDecoder(CSS3ColorDecoder):
See <https://drafts.csswg.org/css-color/>_ for more information..
"""
+ __extended_hex_support__ = True
+
rebeccapurple = _rgb('#663399')
def hwb(
diff --git a/thcolor/colors.py b/thcolor/colors.py
index 79394dd..c0a59c4 100644
--- a/thcolor/colors.py
+++ b/thcolor/colors.py
@@ -328,6 +328,30 @@ class SRGBColor(Color):
):
super().__init__(alpha)
+ try:
+ red = float(red)
+ except (TypeError, ValueError):
+ raise ValueError(f'red should be a float, is {red!r}')
+ else:
+ if red < 0 or red > 1:
+ raise ValueError('red should be between 0.0 and 1.0')
+
+ try:
+ green = float(green)
+ except (TypeError, ValueError):
+ raise ValueError(f'green should be a float, is {green!r}')
+ else:
+ if green < 0 or green > 1:
+ raise ValueError('green should be between 0.0 and 1.0')
+
+ try:
+ blue = float(blue)
+ except (TypeError, ValueError):
+ raise ValueError(f'blue should be a float, is {blue!r}')
+ else:
+ if blue < 0 or blue > 1:
+ raise ValueError('blue should be between 0.0 and 1.0')
+
self._red = red
self._green = green
self._blue = blue
diff --git a/thcolor/decoders.py b/thcolor/decoders.py
index 4f1a7e6..4092007 100644
--- a/thcolor/decoders.py
+++ b/thcolor/decoders.py
@@ -403,8 +403,13 @@ _colorexpressionpattern = _re.compile(
)
-def _get_color_tokens(string: str):
- """ Get color tokens. """
+def _get_color_tokens(string: str, extended_hex: bool = False):
+ """ Get color tokens.
+
+ :param string: The string to get the color tokens from.
+ :param extended_hex: Whether 4 or 8-digit hex colors are
+ allowed (``True``) or not (``False``).
+ """
start: int = 0
was_call_end: bool = False
@@ -491,6 +496,12 @@ def _get_color_tokens(string: str):
)
elif result['hex'] is not None:
value_s = result['hex']
+ if len(value_s) in (4, 8) and not extended_hex:
+ raise _ColorExpressionSyntaxError(
+ f'extended hex values are forbidden: {"#" + value_s!r}',
+ column=start,
+ )
+
if len(value_s) <= 4:
value_s = ''.join(map(lambda x: x + x, value_s))
@@ -617,6 +628,8 @@ class ColorDecoder(_Mapping):
instanciation of each class.
* ``__ncol_support__``: defines whether natural colors (NCol) are
supported while decoding or not.
+ * ``__extended_hex_support__``: defines whether 4 or 8-digit
+ hexadecimal colors (starting with a '#') are allowed or not.
* ``__defaults_to_netscape_color``: defines whether color decoding
defaults to Netscape color parsing or not.
@@ -627,6 +640,7 @@ class ColorDecoder(_Mapping):
__slots__ = ('_mapping',)
__mapping__: _Mapping = {}
__ncol_support__: bool = False
+ __extended_hex_support__: bool = False
__defaults_to_netscape_color__: bool = True
def __init__(self):
@@ -638,6 +652,7 @@ class ColorDecoder(_Mapping):
self._mapping = mapping
self._ncol_support = cls.__ncol_support__
+ self._extended_hex_support = cls.__extended_hex_support__
self._defaults_to_netscape_color = cls.__defaults_to_netscape_color__
def __getattr__(self, key):
@@ -680,6 +695,7 @@ class ColorDecoder(_Mapping):
global _color_pattern
ncol_support = bool(self._ncol_support)
+ extended_hex_support = bool(self._extended_hex_support)
defaults_to_netscape = bool(self._defaults_to_netscape_color)
# Parsing stage; the results will be in ``current``.
@@ -708,7 +724,10 @@ class ColorDecoder(_Mapping):
return '<implicit ncol function>'
return func_stack[0].value
- token_iter = _get_color_tokens(expr)
+ token_iter = _get_color_tokens(
+ expr,
+ extended_hex=extended_hex_support,
+ )
for token in token_iter:
if (
token.type_ == _ColorExpressionToken.TYPE_NCOL
@@ -1040,6 +1059,7 @@ class _MetaColorDecoderType(_ABCMeta):
elements = {}
options = {
'__ncol_support__': False,
+ '__extended_hex_support__': False,
'__defaults_to_netscape_color__': False,
}
@@ -1196,8 +1216,9 @@ class _MetaColorDecoderType(_ABCMeta):
class MetaColorDecoder(ColorDecoder, metaclass=_MetaColorDecoderType):
""" Base meta color decoder, which gets the function and things. """
- __defaults_to_netscape_color__ = True
__ncol_support__ = False
+ __extended_hex_support__ = False
+ __defaults_to_netscape_color__ = True
# End of file.
diff --git a/thcolor/utils.py b/thcolor/utils.py
index cf7173d..f18482e 100644
--- a/thcolor/utils.py
+++ b/thcolor/utils.py
@@ -20,13 +20,19 @@ def rgb(x):
)
-def factor(x, max_: int = 100):
+def factor(x, max_: int = 100, clip: bool = False):
""" Return a factor based on if something is a float or an int. """
if isinstance(x, float):
- return x
- if x in (0, 1) and max_ == 100:
- return float(x)
- return x / max_
+ pass
+ elif x in (0, 1) and max_ == 100:
+ x = float(x)
+ else:
+ x /= max_
+
+ if clip:
+ x = max(0, min(1, x))
+
+ return x
# End of file.