-
-
Notifications
You must be signed in to change notification settings - Fork 343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fail_after
deadline is set on initialization not context entry
#2512
Comments
So don't do that? I fail to see any good design where creating a context manager and then not using it would make sense. |
Often, we'll create a context manager ahead of time (during a configuration step, for example) then downstream enter the context. In my application, we are using If we weren't ever using the context manager, this wouldn't be an issue. The issue here is that the default behavior is antithetical to typical context manager behavior. It's like having the following return the amount of time since initialization rather than within the context: timer = timer()
with timer:
... It's also not an atypical design to use things like an |
Trio would have to change their semantics from what has been documented, and so far there haven't been any practical use cases that would warrant this. |
@agronholm can you link to the documentation that covers this behavior? I did not see any explicit mention of this. |
Here: https://trio.readthedocs.io/en/stable/reference-core.html#trio.fail_after
Implies that the cancel scope gets created with a set deadline. Says nothing about the deadline getting set when entering the scope. |
Ah I think that can be interpreted either way based on your assumptions.. the example shows |
As there are 0 examples of separating the instantiation of this context manager from its use in a |
If it was not a supported use-case then what is the objection to changing the behavior to be clearer? |
To be clear: I can work around this and will need to do so for compatibility with older versions of anyio/trio no matter what is decided here. I will likely add my own utility with the behavior I need — I am only advocating for an API that is less likely to be misleading here. |
If anybody anywhere is already using the context manager in such a disjointed manner correctly, their code will be broken. I wouldn't expect anybody to be doing that, but then again they wouldn't report that to us unless something wasn't working. I also didn't expect anybody to be using the cm like this at all, so who knows? |
I think a change in semantics should be considered but only if someone brings forth a plausible use case where doing this is necessary or at least beneficial. |
Yeah unfortunately timeouts are kind of fuzzy in the first place — we had it like this for a long time before we got a bug report from a user. From a cursory search on GitHub, I don't see any uses apart from ours where the initialization and entry are separated. I'll open a pull request to document this caveat. We can see if more people chime in on this issue, I see no reason to rush an API change. |
I don't think there's any problem necessarily with calculating the deadline at the last moment, though I can imagine someone being confused the other way as well. ("I created the BTW, re:
Trio accepts |
I'd vote +0.25 for changing the behavior (but +1 for documenting things more stringently).
You can easily calculate an absolute timeout at that time instead. The way things currently are, you can't achieve the behavior @madkinsz wants as easily, thus this'd be a net win for that kind of flexibility in case anybody ever wants it. |
Thanks for the additional responses!
Definitely! I plan on doing this in the short term. For more context: I'm also working on a refactor of how we're orchestrating user code to reduce the duplication of some complex portions of code and something I'm exploring is passing a list of contexts to a function that uses an exit stack to enter them all. This separation of configuration of the contexts that should be active during execution of the user code and management of actual execution of the code greatly simplifies our runtime logic. Of course, I can make this accept |
I think it would make sense for Either way, we should document the chosen semantics. |
Concretely thinking about possible ways of going about implementing a change in behaviour (sorry if somewhat rambly/stream-of-thought, I think I personally prefer the new class that transforms into a cancelscope) new attributeOne option would be introducing an attribute, if self.relative: self._deadline = trio.current_time() + self._deadline
Could also add an attribute new class that transforms into
|
I think a new subclass would work well. On the |
I favor adding a
Modifying the deadline or relative deadline before entering seems fine, though I'm still using a leading underscore to discourage the latter. We could make the relative deadline a property so that attempting to modify it after entering checks |
After being entered, modifying either the absolute or relative deadline seems reasonable to me - it'd just implicitly fetch the current time then set the other to match. |
Finishing up the PR, when I realized that the behaviour of with CancelScope(relative_deadline = 5) as cs:
await trio.sleep(1)
print(cs.relative_deadline) # should this print 5, or 4?
cs.relative_deadline = 3 # does this mean "deadline in 3 seconds", or "3 seconds after entering"? My first intuition (and implementation) was that it would print 5, and then "deadline in 3 seconds" - but that means that the value of with CancelScope(relative_deadline = 5) as cs:
await trio.sleep(random.randint(3))
cs.relative_deadline = 1 + random.randint(3)
await trio.sleep(random.randint(3))
print(cs.relative_deadline) # this value now has zero relation to when the scope will time out. Possible alternatives:
I think the first one might be more intuitive and useful? But can see a case for any of the options. I'll push to #3010 soonish with an implementation. |
This is a duplicate of agronholm/anyio#514 — they are following the convention established here in trio.
When using a
fail_after
context, the deadline is set at "initialization" time rather than__enter__
. This behavior can result in unexpected bugs if the context is declared before it is entered. This is not particularly intuitive for a Python context manager — I'd expect the timer to start when the context is entered. I do not think changing it would be complex, but it could be considered breaking.The text was updated successfully, but these errors were encountered: