diff options
Diffstat (limited to 'thcolor/_ref.py')
-rwxr-xr-x | thcolor/_ref.py | 142 |
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 |