aboutsummaryrefslogtreecommitdiff
path: root/thcolor/_ref.py
diff options
context:
space:
mode:
Diffstat (limited to 'thcolor/_ref.py')
-rwxr-xr-xthcolor/_ref.py142
1 files changed, 125 insertions, 17 deletions
diff --git a/thcolor/_ref.py b/thcolor/_ref.py
index 19a469c..beb97fe 100755
--- a/thcolor/_ref.py
+++ b/thcolor/_ref.py
@@ -8,6 +8,7 @@
from inspect import (getfullargspec as _getfullargspec,
getmembers as _getmembers, ismethod as _ismethod)
from itertools import count as _count
+from warnings import warn as _warn
from ._angle import Angle as _Angle
from ._sys import netscape_color as _netscape_color
@@ -93,7 +94,12 @@ class Reference:
return self.__name
class number(metaclass = base_type):
- """ The number type. """
+ """ Syntaxical element for expression decoding, representing
+ a number, integer or decimal, positive or negative.
+
+ This element is usually used to represent a byte value,
+ a factor (usually from 0.0 to 1.0), a color or an angle
+ in degrees. """
def __init__(self, value):
if type(value) == str:
@@ -106,7 +112,12 @@ class Reference:
else:
self._strvalue = str(value)
+ def __str__(self):
+ return self._strvalue
+
def to_byte(self):
+ """ Make a byte (from 0 to 255) out of the number. """
+
try:
value = int(self._value)
@@ -119,6 +130,8 @@ class Reference:
return value
def to_factor(self):
+ """ Make a factor (usually from 0.0 to 1.0) out of the number. """
+
try:
assert 0.0 <= self._value <= 1.0
except:
@@ -127,15 +140,19 @@ class Reference:
return self._value
- def to_color(self):
- r, g, b = _netscape_color(self._strvalue)
- Color = _get_color_class()
- return Color(Color.Type.RGB, r, g, b, 1.0)
-
def to_hue(self):
+ """ Make an angle in degrees out of the number. """
+
return _Angle(_Angle.Type.DEG, self._value)
class percentage(metaclass = base_type):
+ """ Syntaxical element for expression decoding, representing
+ a percentage (number followed by a '%' sign).
+
+ This element is usually used to represent a factor (usually
+ from 0% to 100%) or anything that can be factored such as a
+ byte value (where 0% represents 0 and 100% represents 255). """
+
def __init__(self, value):
self._value = value
@@ -147,10 +164,9 @@ class Reference:
def __repr__(self):
return f"{self._value} %"
- def to_byte(self):
- return int(min(self._value / 100, 1.0) * 255)
-
def to_factor(self):
+ """ Make a factor (usually from 0.0 to 1.0) out of the number. """
+
try:
assert 0 <= self._value <= 100
except:
@@ -159,7 +175,21 @@ class Reference:
return self._value / 100
+ def to_byte(self):
+ """ Make a byte (from 0 to 255) out of the number. """
+
+ if self._value < 0:
+ self._value = 0
+ if self._value > 100:
+ self._value = 100
+
+ return int(min(self._value / 100, 1.0) * 255)
+
class angle(metaclass = base_type):
+ """ Syntaxical element for expression decoding, representing
+ an angle (a number followed by an angle unit: degrees, gradiants,
+ radiants or turns). """
+
def __init__(self, value):
if not isinstance(value, _Angle):
raise TypeError("expected an Angle instance")
@@ -170,9 +200,21 @@ class Reference:
return repr(self._value)
def to_hue(self):
+ """ Get the :class:`thcolor.Angle` object. """
+
return self._value
class color(metaclass = base_type):
+ """ Syntaxical element for expression decoding, representing
+ a color using several methods:
+
+ - a hexadecimal code preceeded by a '#', e.g. "#123ABC".
+ - a natural color (see
+ `NCol <https://www.w3schools.com/colors/colors_ncol.asp>`_).
+ - a color name as defined by a :class:`Reference`.
+ - a legacy color name using the legacy color algorithm (or
+ 'Netscape' color algorithm). """
+
def __init__(self, value):
if not isinstance(value, _get_color_class()):
raise ValueError("expected a Color instance")
@@ -183,6 +225,8 @@ class Reference:
return repr(self._value)
def to_color(self):
+ """ Get the :class:`thcolor.Color` object. """
+
return self._value
# ---
@@ -190,8 +234,18 @@ class Reference:
# ---
def _get_functions(self):
- """ The functions getter, for getting a function using its
- name. """
+ """ Function getter, which can be used as ``.functions[name](argsā€¦)``.
+
+ Provides a wrapper to the method which checks the argument
+ types and perform the necessary conversions before passing
+ them to the functions.
+
+ For example, with a classical CSS reference named ``ref``:
+
+ >>> ref.functions['rgb'](ref.number(18), ref.number(52), """ \
+ """ref.number(86))
+ ... Color(type = Color.Type.RGB, red = 18, green = 52, """ \
+ """blue = 86, alpha = 1.0) """
class _FunctionGetter:
def __init__(self, ref):
@@ -270,7 +324,7 @@ class Reference:
if Reference.color in exp:
try:
- args[-1] = arg.to_color()
+ args[-1] = self._fref.colors[arg]
except:
pass
else:
@@ -286,14 +340,60 @@ class Reference:
return _FunctionGetter(self)
def _get_colors(self):
- """ The colors getter, for getting a named color. """
+ """ Colors getter, which can be used as ``.colors[value]``.
+ For example, with a classical CSS reference named ``ref``:
+
+ >>> ref.colors['blue']
+ ... Color(type = Color.Type.RGB, red = 0, green = 0, """ \
+ """blue = 255, alpha = 1.0)
+ >>> ref.colors[thcolor.Reference.color(""" \
+ """thcolor.Color.from_text('#123456'))]
+ ... Color(type = Color.Type.RGB, red = 18, green = 52, """ \
+ """blue = 86, alpha = 1.0) """
class _ColorGetter:
def __init__(self, ref):
self._cref = ref
- def __getitem__(self, name):
- return self._cref._color(name)
+ def __getitem__(self, key):
+ try:
+ return key.to_color()
+ except AttributeError:
+ pass
+
+ try:
+ name = str(key)
+ except:
+ raise KeyError(repr(key))
+
+ try:
+ value = self._cref._color(name)
+ except KeyError:
+ pass
+ except Exception as e:
+ _warn(RuntimeWarning, f"{self.__class__.__name__} " \
+ f"returned exception {e.__class__.__name__} instead " \
+ f"of KeyError for color name {repr(name)}.")
+ pass
+ else:
+ try:
+ assert isinstance(value, _get_color_class())
+ except AssertionError:
+ _warn(RuntimeWarning, f"{self.__class__.__name__} " \
+ f"returned non-Color value {repr(value)} for " \
+ f"color name {repr(name)}, ignoring.")
+ else:
+ return value
+
+ try:
+ r, g, b = _netscape_color(name)
+ except:
+ pass
+ else:
+ Color = _get_color_class()
+ return Color(Color.Type.RGB, r, g, b)
+
+ raise KeyError(repr(key))
return _ColorGetter(self)
@@ -305,12 +405,20 @@ class Reference:
# ---
def _color(self, name):
- """ Get a named color. """
+ """ Name color getter used behind the
+ :attr:`thcolor.Reference.colors` getter, ought to be overriden
+ by superseeding classes.
+
+ These classes should return ``super()._color(name)`` in case
+ they have no match for the given name. """
raise KeyError(f'{name}: no such color')
def default():
- """ Get the default reference. """
+ """ Static method for gathering the default reference, by
+ default :class:`thcolor.DefaultReference`. Is only used on
+ the base :class:`thcolor.Reference` type and shall not be
+ overriden. """
global _default_reference