Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 57 additions & 26 deletions src/miniflask/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,28 @@ def __init__(self, mf, optional=False):
self._mf = mf
self.optional_value = optional
self.hook = {}
self._data = {}
super().__init__()

def make_dummy_fn(self, name, call_before_after=True):
def make_dummy_fn(self, name, call_before_after=True): # noqa: C901 too-complex pylint: disable=too-many-statements
# automatic before/after events
name_before = 'before_' + name
name_after = 'after_' + name
has_before = name_before in self._mf.event_objs and call_before_after
has_after = name_after in self._mf.event_objs and call_before_after
fn_after = getattr(self._mf.event, name_after) if has_after else None
fn_before = getattr(self._mf.event, name_before) if has_before else None

# ensure attached events are created
if has_before:
getattr(self._mf.event, name_before)
if has_after:
getattr(self._mf.event, name_after)

def dummy_fn(*args, altfn=None, _event_overwrite=None, **kwargs):
if callable(altfn):

# call before_-event functions
if has_before:
for fn_b in fn_before.subevents:
for fn_b in self._data[name_before]["wrapped_single_events"]:
if fn_b.needs_event_obj:
event_call = eventCall(self, name, args, kwargs)
fn_b(_event_overwrite=event_call)
Expand All @@ -58,7 +63,7 @@ def dummy_fn(*args, altfn=None, _event_overwrite=None, **kwargs):

# call after_-event functions
if has_after:
for fn_a in fn_after.subevents:
for fn_a in self._data[name_after]["wrapped_single_events"]:
if fn_a.needs_event_obj:
event_call = eventCall(self, name, args, kwargs, result=result)
fn_a(_event_overwrite=event_call)
Expand Down Expand Up @@ -104,6 +109,15 @@ def __getattr__(self, name): # noqa: C901 too-complex pylint: disable=too-many
- `event.optional.eventname(..., altfn=...)` treats the event like a `unique` event, but in case no event was defined, it uses altfn to parse the arguments.
# .{.end}

# Internal Event Data
The `event` object contains a hidden `_data` dictionary that saves the information needed to construct the events from the actual code.
In more detail:
- `event._data[eventname]` contains the dictionary with all information required to construct the events
- `event._data[eventname]["modules"]`: list of modules that define the event `eventname`
- `event._data[eventname]["wrapped_event"]`: symlink to `event.eventname`
- `event._data[eventname]["wrapped_single_events"]`: list of all wrapped events in case of non-unique event `eventname`
- `event._data[eventname]["raw_functions"]`: list of all raw functions (as defined in code) in the modules given above (same order as in the modules list)
- `event._data[eventname]["raw_function_args"]`: the `mf`, `state` and `event` objects arguments needed for the raw functions

### Performance Note {.alert}
Leaving the `event`, `state` and `mf` arguments out from an event function definition removes an extra function wrapper around every function. Thus, without them the time consumption should not differ at all from a normal function call.
Expand All @@ -122,6 +136,10 @@ def __getattr__(self, name): # noqa: C901 too-complex pylint: disable=too-many
if not self.optional_value:
raise AttributeError("The Event '%s' has not been registered yet." % name)
fn_wrap = self.make_dummy_fn(name, call_before_after=True)
modules_of_single_events = ["dummy-module"]
wrapped_single_events = [fn_wrap]
raw_events = [lambda:[]]
mf_args = []

else:

Expand Down Expand Up @@ -158,10 +176,14 @@ def fn_wrap_scope(fn, _mf, _state, _event, module, needed_locals=None, miniflask
name_after = 'after_' + name
has_before = name_before in self._mf.event_objs and call_before_after
has_after = name_after in self._mf.event_objs and call_before_after
fn_after = getattr(self._mf.event, name_after) if has_after else None
fn_before = getattr(self._mf.event, name_before) if has_before else None
miniflask_args_event_i = -1

# ensure attached events are created
if has_before:
getattr(self._mf.event, name_before)
if has_after:
getattr(self._mf.event, name_after)

# get index of "state" / "event"
for i in range(min(len(arg_names), 3)):
for var, varname in [(_mf, "mf"), (_state, "state"), (_event, "event")]:
Expand Down Expand Up @@ -189,7 +211,7 @@ def fn_wrap(*args, altfn=None, _event_overwrite=None, **kwargs):

# call before_-event functions
if has_before:
for fn_b in fn_before.subevents:
for fn_b in self._data[name_before]["wrapped_single_events"]:
if fn_b.needs_event_obj:
event_call = eventCall(self, name, args, kwargs)
fn_b(_event_overwrite=event_call)
Expand All @@ -208,7 +230,7 @@ def fn_wrap(*args, altfn=None, _event_overwrite=None, **kwargs):

# call after_-event functions
if has_after:
for fn_a in fn_after.subevents:
for fn_a in self._data[name_after]["wrapped_single_events"]:
if fn_a.needs_event_obj:
event_call = eventCall(self, name, args, kwargs, result=result)
fn_a(_event_overwrite=event_call)
Expand All @@ -225,7 +247,7 @@ def fn_wrap(*args, altfn=None, _event_overwrite=None, **kwargs):

# call before_-event functions
if has_before:
for fn_b in fn_before.subevents:
for fn_b in self._data[name_before]["wrapped_single_events"]:
if fn_b.needs_event_obj:
event_call = eventCall(self, name, args, kwargs)
fn_b(_event_overwrite=event_call)
Expand All @@ -244,7 +266,7 @@ def fn_wrap(*args, altfn=None, _event_overwrite=None, **kwargs):

# call after_-event functions
if has_after:
for fn_a in fn_after.subevents:
for fn_a in self._data[name_after]["wrapped_single_events"]:
if fn_a.needs_event_obj:
event_call = eventCall(self, name, args, kwargs, result=result)
fn_a(_event_overwrite=event_call)
Expand All @@ -265,7 +287,7 @@ def fn_wrap(*args, altfn=None, _event_overwrite=None, **kwargs):

# call before_-event functions
if has_before:
for fn_b in fn_before.subevents:
for fn_b in self._data[name_before]["wrapped_single_events"]:
if fn_b.needs_event_obj:
event_call = eventCall(self, name, args, kwargs)
fn_b(_event_overwrite=event_call)
Expand All @@ -278,7 +300,7 @@ def fn_wrap(*args, altfn=None, _event_overwrite=None, **kwargs):

# call after_-event functions
if has_after:
for fn_a in fn_after.subevents:
for fn_a in self._data[name_after]["wrapped_single_events"]:
if fn_a.needs_event_obj:
event_call = eventCall(self, name, args, kwargs, result=result)
fn_a(_event_overwrite=event_call)
Expand Down Expand Up @@ -308,10 +330,9 @@ def fn_wrap(*args, altfn=None, _event_overwrite=None, **kwargs):
if eobj.unique:
fn_wrap, has_signature, mf_args = fn_wrap_scope(eobj.fn, eobj.modules, eobj.modules.state, eobj.modules.event, eobj.modules)
if has_signature:
setattr(fn_wrap, 'mf_modules', [eobj.modules.module_id])
setattr(fn_wrap, 'subevents', [fn_wrap])
setattr(fn_wrap, 'fns', [eobj.fn])
setattr(fn_wrap, 'fns_args', [mf_args])
modules_of_single_events = [eobj.modules.module_id]
wrapped_single_events = [fn_wrap]
raw_events = [eobj.fn]
else:
def multiple_fn_wrap_scope(orig_fns, modules=eobj.modules):
fns, have_signature, mf_args = zip(*[fn_wrap_scope(fn, _mf=module, _state=module.state, _event=module.event, module=module, skip_twice=True, call_before_after=False) for fn, module in zip(orig_fns, modules)])
Expand All @@ -321,15 +342,19 @@ def multiple_fn_wrap_scope(orig_fns, modules=eobj.modules):
name_after = 'after_' + name
has_before = name_before in self._mf.event_objs and call_before_after
has_after = name_after in self._mf.event_objs and call_before_after
fn_after = getattr(self._mf.event, name_after) if has_after else None
fn_before = getattr(self._mf.event, name_before) if has_before else None

# ensure attached events are created
if has_before:
getattr(self._mf.event, name_before)
if has_after:
getattr(self._mf.event, name_after)

def fn_wrap(*args, altfn=None, **kwargs):
del altfn # unused

# call before_-event functions
if has_before:
for fn_b in fn_before.subevents:
for fn_b in self._data[name_before]["wrapped_single_events"]:
if fn_b.needs_event_obj:
event_call = eventCall(self, name, args, kwargs)
fn_b(_event_overwrite=event_call)
Expand All @@ -344,7 +369,7 @@ def fn_wrap(*args, altfn=None, **kwargs):

# call after_-event functions
if has_after:
for fn_a in fn_after.subevents:
for fn_a in self._data[name_after]["wrapped_single_events"]:
if fn_a.needs_event_obj:
event_call = eventCall(self, name, args, kwargs, result=results)
fn_a(_event_overwrite=event_call)
Expand All @@ -357,11 +382,17 @@ def fn_wrap(*args, altfn=None, **kwargs):
return fn_wrap, fns, have_signature, mf_args

fn_wrap, fns, have_signature, mf_args = multiple_fn_wrap_scope(eobj.fn)
setattr(fn_wrap, 'mf_modules', [m.module_id for m, has_sig in zip(eobj.modules, have_signature) if has_sig])
setattr(fn_wrap, 'subevents', [fn for fn, has_sig in zip(fns, have_signature) if has_sig])
setattr(fn_wrap, 'fns', eobj.fn)
setattr(fn_wrap, 'fns_args', [mf_args])

modules_of_single_events = [m.module_id for m, has_sig in zip(eobj.modules, have_signature) if has_sig]
wrapped_single_events = [fn for fn, has_sig in zip(fns, have_signature) if has_sig]
raw_events = eobj.fn

self._data[name] = {
"modules": modules_of_single_events,
"wrapped_event": fn_wrap,
"wrapped_single_events": wrapped_single_events,
"raw_function_args": mf_args,
"raw_functions": raw_events,
}
setattr(self, name, fn_wrap)
return fn_wrap

Expand Down
1 change: 1 addition & 0 deletions src/miniflask/miniflask.py
Original file line number Diff line number Diff line change
Expand Up @@ -1408,6 +1408,7 @@ def unregister_event(self, name: str, only_cache: bool = False, keep_attached_ev
""" # noqa: W291
if hasattr(self.event, name):
delattr(self.event, name)
del self.event._data[name]
if not only_cache and name in self.event_objs:
del self.event_objs[name]
if not keep_attached_events and "before_" + name in self.event_objs:
Expand Down
5 changes: 3 additions & 2 deletions tests/features/modules/a/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ def test():


def main(event):
print(event.test.mf_modules)
print(event.test.fns)
event.test()
print(event._data["test"]["modules"])
print(event._data["test"]["raw_functions"])
print(event["modules.a"])
print(event.optional["modules.a"])
print(event.optional.test())
Expand Down
5 changes: 3 additions & 2 deletions tests/features/modules/b/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ def test():


def main(event):
print(event.test.mf_modules)
print(event.test.fns)
event.test()
print(event._data["test"]["modules"])
print(event._data["test"]["raw_functions"])
print(event["modules.a"])
print(event.optional["modules.a"])

Expand Down