Skip to content

Commit

Permalink
Preliminary Lambda-like support for callbacks (#33)
Browse files Browse the repository at this point in the history
Added preliminary rich callback support for callbacks.

Co-authored-by: ObaraEmmanuel <[email protected]>
  • Loading branch information
KavyanshKhaitan2 and ObaraEmmanuel authored May 29, 2024
1 parent 1b15777 commit b51f3fc
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
25 changes: 17 additions & 8 deletions formation/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# ======================================================================= #
# Copyright (c) 2020 Hoverset Group. #
# ======================================================================= #
import functools
import logging
import os
import warnings
Expand All @@ -17,7 +18,7 @@
from formation.meth import Meth
from formation.handlers.image import parse_image
from formation.handlers.scroll import apply_scroll_config
from formation.utils import is_class_toplevel, is_class_root
from formation.utils import is_class_toplevel, is_class_root, callback_parse, event_handler
import formation

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -84,7 +85,7 @@ def _get_class(cls, node):

if hasattr(module, impl):
return getattr(module, impl)
raise AttributeError("class {} not found in module {}".format(impl, module))
raise AttributeError("class {} in module {}".format(impl, module))

@classmethod
def load(cls, node, builder, parent):
Expand Down Expand Up @@ -425,24 +426,32 @@ def on_keypress(self, event):
}
for widget, events in self._event_map.items():
for event in events:
handler = callback_map.get(event.get("handler"))
handler_string = event.get("handler")
parsed = callback_parse(handler_string)

# parsed[0] is the function name.
handler = callback_map.get(parsed[0])
if handler is not None:
# parsed[1] is function args/ parsed[2] is function kwargs.
partial_handler = functools.partial(event_handler, func=handler, args=parsed[1], kwargs=parsed[2])
widget.bind(
event.get("sequence"),
handler,
partial_handler,
event.get("add")
)
else:
logger.warning("Callback '%s' not found", event.get("handler"))
logger.warning("Callback '%s' not found", parsed[0])

for prop, val, handle_method in self._command_map:
handler = callback_map.get(val)
parsed = callback_parse(val)
handler = callback_map.get(parsed[0])
if handle_method is None:
raise ValueError("Handle method is None, unable to apply binding")
if handler is not None:
handle_method(**{prop: handler})
partial_handler = functools.partial(handler, *parsed[1], **parsed[2])
handle_method(**{prop: partial_handler})
else:
logger.warning("Callback '%s' not found", val)
logger.warning("Callback '%s' not found", parsed[0])

def load_path(self, path):
"""
Expand Down
23 changes: 23 additions & 0 deletions formation/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,26 @@ def __setitem__(self, key, value):
getattr(self, self.prop_info[key]["setter"])(value)
else:
super().__setitem__(key, value)


def event_handler(e, func, args, kwargs):
"""
A utility function to handle events and pass them to the
appropriate callback function with the event object as the first argument.
"""
return func(e, *args, **kwargs)


def callback_parse(command: str):
"""
Returns parts of a command after parsing it using eval method.
:param command: A string in the form ``funcname arg1, arg2, arg3, ..., kwarg1=value, kwarg2=value, ...``
:return: A tuple containing (funcname, args, kwargs)
"""

command_list: list = command.split(' ')
command_func: str = command_list.pop(0)
command_string = ",".join(command_list).strip(",")
args, kwargs = eval(f'(lambda *args, **kwargs: (args, kwargs))({command_string})')
return command_func, args, kwargs

0 comments on commit b51f3fc

Please sign in to comment.