Fail fast on unsupported lambda/partial callbacks in schedule_event#3320
Fail fast on unsupported lambda/partial callbacks in schedule_event#3320
Conversation
|
It was a deliberate design choice not to allow lambdas, and this behavior is documented. I would need strong reasons to change my mind on this. |
|
Performance benchmarks:
|
My concern is only that |
But that is not what this PR does. It creates an internal hard ref for weak references. Also, the same issue as lambdas also holds potentially for partial functions. I am potentially open to accepting that lambdas and partials raise a value error when passed to an event. |
I suggest fail-fast validation instead: reject unsupported ephemeral callables at event creation (at least lambdas and What are your thoughts? |
This is exactly what I was trying to suggest. |
|
Should I refactor this PR then? |
|
Performance benchmarks:
|
|
Thanks for the update. I have been looking at this issue myself as well for some other reasons.
|
|
There is no way to check whether a partial was “assigned to a variable” in a way that guarantees safe lifetime. |
|
The other option is to issue a warning if the weakref resolves to None. Warnings in general are issued only once, but it would allow users to more quickly diagnose that something might be wrong. |
|
I would suggest approaching this slightly differently: if isinstance(function, MethodType):
function = WeakMethod(function)
else:
function = ref(function)
if function() is None:
# error message needs work
raise TypeError(function is not weakly referencable ...)
self.fn = functionSo rather than checking the type and everything, we just check if we can take a weakref to the function at creation. If we can do that, we accept it. Otherwise, we raise an error. In this way, partials assigned to a variable are still accepted. |
|
I like the direction, but I want to flag one concern: validating weakref resolution at creation time is only a point-in-time check. A callback can still be GC’d before execution, so we may still get nondeterministic no-ops. |
Yes, but that is desirable behavior. Imagine you schedule events for an agent. Somewhere along the way, this agent is removed from the simulation. All events that call this agent now must either be removed or fail silently. With weakrefs, we get silent failures. Not sure about the warning. I think it might be more confusing than helpful. |
|
Can you update the starting post to align with the final implementation? |
|
The behavior is still not exactly what I have in mind. Let me try to explain it
This last one is the sticky one and also in my own testing I can't seem to get it right. Basically, a = partial(my_func, 1,2,3)
Event(5, a)should run fine. |
|
Thanks, this helps clarify the intended behavior. if not callable -> |
|
We hit cross-platform instability with the current inline- So the check is not deterministic in CI.
This keeps fail-fast behavior without flaky platform-dependent failures. |
6fe3571 to
29179f8
Compare
|
code wise, it seems fine now. I want to find some time to test a few things manually on this brach before approving it. |
|
the docs are breaking because the event scheduling tutorial is breaking because it uses lambda functions. Can you take a look at fix this? |
|
Fixed it. |
|
@quaquel backport? |
Summary
Aligns
Eventcallback handling with the weakref-based design: callbacks are accepted based on weakref capability (not callable type), and callback lifetime semantics are explicitly documented.Bug / Issue
Closes #3319
The final agreed behavior is to preserve weakref semantics: callbacks may no-op if the target is garbage-collected before execution.
This PR updates implementation/tests/docs to match that contract and avoids type-based rejection of valid callables like
functools.partial.Implementation
Updated
events.py:_create_callable_reference).__setstate__.WeakMethod).Updated tests:
test_schedule_run.pytest_devs.pyTesting
test_schedule_run.py: 22 passedtest_dev.py: 23 passedAdditional Notes