aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Touhey <thomas@touhey.fr>2022-01-01 12:19:41 +0100
committerThomas Touhey <thomas@touhey.fr>2022-01-01 12:22:50 +0100
commit246036d0133f8e75562d2ded973a1c937c2faa52 (patch)
tree162f269bb298d27fa530f1a20adaab0f7393f999
parentabbfaaff3ea7d19a36933898ec2c11df00b6f4c5 (diff)
More tests on decoders, added a few more conversions.
-rw-r--r--setup.cfg2
-rwxr-xr-xtests/test_decoders.py31
-rw-r--r--thcolor/colors.py25
-rw-r--r--thcolor/decoders.py40
4 files changed, 91 insertions, 7 deletions
diff --git a/setup.cfg b/setup.cfg
index 6211e52..4c774a5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -35,7 +35,7 @@ source-dir = docs
universal = True
[flake8]
-ignore = D105,D107,D202,D208,D210,D401,T499,W503
+ignore = D105,D107,D202,D208,D210,D401,T484,T499,W503
exclude =
docs/conf.py
test.py
diff --git a/tests/test_decoders.py b/tests/test_decoders.py
index 2f89316..9cf120f 100755
--- a/tests/test_decoders.py
+++ b/tests/test_decoders.py
@@ -15,6 +15,37 @@ from thcolor.builtin import * # NOQA
from thcolor.errors import * # NOQA
+class TestInvalidDecoders:
+ """ Test the exceptions raised when an invalid decoder is created. """
+
+ def test_unknown_data_type(self):
+ with pytest.raises(TypeError, match=r'neither an alias'):
+ class BogusDecoder(MetaColorDecoder):
+ hello = 'hello'
+
+ def test_circular_aliases(self):
+ with pytest.raises(ValueError, match=r'cyclic dependency'):
+ class BogusDecoder(MetaColorDecoder):
+ a = alias('b')
+ b = alias('a')
+
+ def test_alias_unknown_argument(self):
+ with pytest.raises(ValueError, match=r'not an argument'):
+ class BogusDecoder(MetaColorDecoder):
+ def f(a: int) -> int:
+ return a
+
+ g = alias('f', args=('b',))
+
+ def test_alias_non_default_argument(self):
+ with pytest.raises(ValueError, match=r'left without value'):
+ class BogusDecoder(MetaColorDecoder):
+ def f(a: int, b: int = 0) -> int:
+ return a + b
+
+ g = alias('f', args=('b',))
+
+
class TestBaseDecoder:
@pytest.fixture
def decoder(self):
diff --git a/thcolor/colors.py b/thcolor/colors.py
index 935dc72..79394dd 100644
--- a/thcolor/colors.py
+++ b/thcolor/colors.py
@@ -564,7 +564,15 @@ class SRGBColor(Color):
def asyiq(self) -> 'YIQColor':
""" Get an YIQColor out of the current object. """
- raise NotImplementedError # TODO
+ r, g, b = self.red, self.green, self.blue
+ y = .3 * r + .59 * g + .11 * b
+
+ return YIQColor(
+ y=y,
+ i=.74 * (r - y) - .27 * (b - y),
+ q=.48 * (r - y) + .41 * (b - y),
+ alpha=self.alpha,
+ )
def asyuv(self) -> 'YUVColor':
""" Get an YUVColor out of the current object. """
@@ -1190,7 +1198,20 @@ class YIQColor(Color):
def assrgb(self) -> 'SRGBColor':
""" Get an SRGBColor out of the current object. """
- raise NotImplementedError # TODO
+ y, i, q = self.y, self.i, self.q
+
+ return SRGBColor(
+ red=max(0.0, min(1.0, (
+ y + .9468822170900693 * i + .6235565819861433 * q
+ ))),
+ green=max(0.0, min(1.0, (
+ y - .27478764629897834 * i - .6356910791873801 * q
+ ))),
+ blue=max(0.0, min(1.0, (
+ y - 1.1085450346420322 * i + 1.7090069284064666 * q
+ ))),
+ alpha=self.alpha,
+ )
def asyiq(self) -> 'YIQColor':
""" Get an YIQColor out of the current object. """
diff --git a/thcolor/decoders.py b/thcolor/decoders.py
index 3aae9cc..4f1a7e6 100644
--- a/thcolor/decoders.py
+++ b/thcolor/decoders.py
@@ -74,7 +74,10 @@ def _issubclass(cls, types):
# We default on the base ``issubclass`` from here.
- return issubclass(cls, types)
+ try:
+ return issubclass(cls, types)
+ except TypeError:
+ return False
def _isinstance(value, types):
@@ -1067,9 +1070,6 @@ class _MetaColorDecoderType(_ABCMeta):
del clsattrs
# Get the elements and aliases from the current attribute dictionary.
- #
- # TODO: check if the argument types are valid (we had ``_angle``
- # versus ``_Angle`` problems before, so we need to check).
aliases = {}
childelements = {}
@@ -1158,6 +1158,38 @@ class _MetaColorDecoderType(_ABCMeta):
elements.update(aliaselements)
elements.update(childelements)
+ # Check the types of the annotations, just in case.
+
+ for key, element in elements.items():
+ try:
+ args_spec = _get_args(element)
+ except TypeError:
+ continue
+
+ for argname, argtype, argdefvalue in args_spec:
+ if argtype is None:
+ continue
+
+ if all(
+ not _issubclass(type_, argtype)
+ for type_ in (int, float, _Color, _Angle, type(None))
+ ):
+ raise TypeError(
+ f'function {key!r}, argument {argname!r}: '
+ 'none of the types handled by the decoder are '
+ f'valid subclasses of type hint {argtype}',
+ )
+
+ if argdefvalue is _NO_DEFAULT_VALUE:
+ continue
+
+ if not _isinstance(argdefvalue, argtype):
+ raise TypeError(
+ f'function {key!r}, argument {argname!r}: '
+ f'default value {argdefvalue!r} is not a valid '
+ f'instance of type hint {argtype!r}',
+ )
+
return cls