-
-
Notifications
You must be signed in to change notification settings - Fork 263
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement support for callbacks in `colour.continuous.AbstractContinu…
…ousFunction` class.
- Loading branch information
Showing
7 changed files
with
332 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
""" | ||
Callback Management | ||
=================== | ||
Defines the callback management objects. | ||
""" | ||
|
||
from __future__ import annotations | ||
|
||
from dataclasses import dataclass | ||
|
||
from colour.hints import ( | ||
Any, | ||
Callable, | ||
) | ||
|
||
__author__ = "Colour Developers" | ||
__copyright__ = "Copyright 2013 Colour Developers" | ||
__license__ = "New BSD License - https://opensource.org/licenses/BSD-3-Clause" | ||
__maintainer__ = "Colour Developers" | ||
__email__ = "colour-developers@colour-science.org" | ||
__status__ = "Production" | ||
|
||
__all__ = [ | ||
"Callback", | ||
"MixinCallback", | ||
] | ||
|
||
|
||
@dataclass | ||
class Callback: | ||
""" | ||
Define a callback. | ||
Parameters | ||
---------- | ||
name | ||
Callback name. | ||
function | ||
Callback callable. | ||
""" | ||
|
||
name: str | ||
function: Callable | ||
|
||
|
||
class MixinCallback: | ||
""" | ||
A mixin providing support for callbacks. | ||
Attributes | ||
---------- | ||
- :attr:`~colour.utilities.MixinCallback.callbacks` | ||
- :attr:`~colour.utilities.MixinCallback.__setattr__` | ||
Methods | ||
------- | ||
- :meth:`~colour.utilities.MixinCallback.register_callback` | ||
- :meth:`~colour.utilities.MixinCallback.unregister_callback` | ||
Examples | ||
-------- | ||
>>> class WithCallback(MixinCallback): | ||
... def __init__(self): | ||
... super().__init__() | ||
... self.attribute_a = "a" | ||
... | ||
>>> with_callback = WithCallback() | ||
>>> def _on_attribute_a_changed(self, name: str, value: str) -> str: | ||
... if name == "attribute_a": | ||
... value = value.upper() | ||
... return value | ||
>>> with_callback.register_callback( | ||
... "on_attribute_a_changed", _on_attribute_a_changed | ||
... ) | ||
>>> with_callback.attribute_a = "a" | ||
>>> with_callback.attribute_a | ||
'A' | ||
""" | ||
|
||
def __init__(self) -> None: | ||
super().__init__() | ||
|
||
self._callbacks: list = [] | ||
|
||
@property | ||
def callbacks(self) -> list: | ||
""" | ||
Getter property for the callbacks. | ||
Returns | ||
------- | ||
:class:`list` | ||
Callbacks. | ||
""" | ||
|
||
return self._callbacks | ||
|
||
def __setattr__(self, name: str, value: Any) -> None: | ||
""" | ||
Set given value to the attribute with given name. | ||
Parameters | ||
---------- | ||
attribute | ||
Attribute to set the value of. | ||
value | ||
Value to set the attribute with. | ||
""" | ||
|
||
if hasattr(self, "_callbacks"): | ||
for callback in self._callbacks: | ||
value = callback.function(self, name, value) | ||
|
||
super().__setattr__(name, value) | ||
|
||
def register_callback(self, name: str, function: Callable) -> None: | ||
""" | ||
Register the callback with given name. | ||
Parameters | ||
---------- | ||
name | ||
Callback name. | ||
function | ||
Callback callable. | ||
Examples | ||
-------- | ||
>>> class WithCallback(MixinCallback): | ||
... def __init__(self): | ||
... super().__init__() | ||
... | ||
>>> with_callback = WithCallback() | ||
>>> with_callback.register_callback("callback", lambda *args: None) | ||
>>> with_callback.callbacks # doctest: +SKIP | ||
[Callback(name='callback', function=<function <lambda> at 0x10fcf3420>)] | ||
""" | ||
|
||
self._callbacks.append(Callback(name, function)) | ||
|
||
def unregister_callback(self, name: str) -> None: | ||
""" | ||
Unregister the callback with given name. | ||
Parameters | ||
---------- | ||
name | ||
Callback name. | ||
Examples | ||
-------- | ||
>>> class WithCallback(MixinCallback): | ||
... def __init__(self): | ||
... super().__init__() | ||
... | ||
>>> with_callback = WithCallback() | ||
>>> with_callback.register_callback("callback", lambda s, n, v: v) | ||
>>> with_callback.callbacks # doctest: +SKIP | ||
[Callback(name='callback', function=<function <lambda> at 0x10fcf3420>)] | ||
>>> with_callback.unregister_callback("callback") | ||
>>> with_callback.callbacks | ||
[] | ||
""" | ||
|
||
self._callbacks = [ | ||
callback for callback in self._callbacks if callback.name != name | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
# !/usr/bin/env python | ||
"""Define the unit tests for the :mod:`colour.utilities.callback` module.""" | ||
|
||
from __future__ import annotations | ||
|
||
import unittest | ||
|
||
from colour.utilities import MixinCallback | ||
|
||
__author__ = "Colour Developers" | ||
__copyright__ = "Copyright 2013 Colour Developers" | ||
__license__ = "New BSD License - https://opensource.org/licenses/BSD-3-Clause" | ||
__maintainer__ = "Colour Developers" | ||
__email__ = "colour-developers@colour-science.org" | ||
__status__ = "Production" | ||
|
||
__all__ = [ | ||
"TestMixinCallback", | ||
] | ||
|
||
|
||
class TestMixinCallback(unittest.TestCase): | ||
""" | ||
Define :class:`colour.utilities.callback.MixinCallback` class unit | ||
tests methods. | ||
""" | ||
|
||
def setUp(self): | ||
"""Initialise the common tests attributes.""" | ||
|
||
class WithCallback(MixinCallback): | ||
"""Test :class:`MixinCallback` class.""" | ||
|
||
def __init__(self): | ||
super().__init__() | ||
|
||
self.attribute_a = "a" | ||
|
||
self._with_callback = WithCallback() | ||
|
||
def _on_attribute_a_changed(self, name: str, value: str) -> str: | ||
"""Transform *self._attribute_a* to uppercase.""" | ||
|
||
if name == "attribute_a": | ||
value = value.upper() | ||
|
||
if getattr(self, name) != "a": | ||
raise RuntimeError( | ||
'"self" was not able to retrieve class instance value!' | ||
) | ||
|
||
return value | ||
|
||
self._on_attribute_a_changed = _on_attribute_a_changed | ||
|
||
def test_required_attributes(self): | ||
"""Test the presence of required attributes.""" | ||
|
||
required_attributes = ("callbacks",) | ||
|
||
for attribute in required_attributes: | ||
self.assertIn(attribute, dir(MixinCallback)) | ||
|
||
def test_required_methods(self): | ||
"""Test the presence of required methods.""" | ||
|
||
required_methods = ( | ||
"__init__", | ||
"register_callback", | ||
"unregister_callback", | ||
) | ||
|
||
for method in required_methods: | ||
self.assertIn(method, dir(MixinCallback)) | ||
|
||
def test_register_callback(self): | ||
""" | ||
Test :class:`colour.utilities.callback.MixinCallback.register_callback` | ||
method. | ||
""" | ||
|
||
self._with_callback.register_callback( | ||
"on_attribute_a_changed", self._on_attribute_a_changed | ||
) | ||
|
||
self._with_callback.attribute_a = "a" | ||
self.assertEqual(self._with_callback.attribute_a, "A") | ||
self.assertEqual(len(self._with_callback.callbacks), 1) | ||
|
||
def test_unregister_callback(self): | ||
""" | ||
Test :class:`colour.utilities.callback.MixinCallback.unregister_callback` | ||
method. | ||
""" | ||
|
||
if len(self._with_callback.callbacks) == 0: | ||
self._with_callback.register_callback( | ||
"on_attribute_a_changed", self._on_attribute_a_changed | ||
) | ||
|
||
self.assertEqual(len(self._with_callback.callbacks), 1) | ||
self._with_callback.unregister_callback("on_attribute_a_changed") | ||
self.assertEqual(len(self._with_callback.callbacks), 0) | ||
self._with_callback.attribute_a = "a" | ||
self.assertEqual(self._with_callback.attribute_a, "a") | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |
Oops, something went wrong.