-
-
Notifications
You must be signed in to change notification settings - Fork 102
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
stdout isnt doesn't unwraped when interupted #212
Comments
Unfortunately, as far as I am aware, the progressbar can't detect these exceptions since they don't happen in code managed by the progressbar. An alternative that does work properly is by using the import progressbar
import time
with progressbar.ProgressBar(redirect_stdout=True) as bar:
for i in bar(range(100)):
print('Some text', i)
time.sleep(0.02)
if i == 50:
raise KeyboardInterrupt |
I ran with the same problem with stderr and using |
@wolph I think that the iterator version could also clean up after itself, by ensuring that finished() is called when a general exceptions would stop the iterator.
Is there a disadvantage to this kind of solution I'm not seeing? I also overrode the |
It's mentioned in the readme part of the docs: https://progressbar-2.readthedocs.io/en/latest/#context-wrapper I agree that the docs can be improved a lot though. The big problem is that my time is quite limited and this project is not the only project that I maintain: https://pypi.org/user/WoLpH/
I agree, context managers are often inconvenient to work with and your
I fail to see how, but I might be missing something here :)
Your code still uses the
That's indeed a bug that needs to be fixed. Good catch! |
Nevermind... all that, thanks to your suggestion I found the answer. I can catch Thanks for the suggestion, I'll fix it soon :) |
For clarity, all I meant by the iterator cleaning up after itself was exactly that it could check for exceptions and ensure finished() is called before quitting. Calling finished() seems to be the best way to ensure that std is unwrapped.
This is true. I think that this is the right place to put the except block ensuring finished() is always called; inside the next method, rather than around the whole iteration. I'm happy to knock together an PR for these changes, or perhaps do them another way if you have a different preference? |
Ah, that's perfect |
I've added the two changes to the development branch, can you test if that does everything you were looking for? :) I'm always happy with pull requests if you have more suggestions of course :) |
@mmcewen-g not sure if you noticed the update so pinging you again :) If it works ok I'll create a new release |
This doesn't work, but it took me a while to work out why. Apologies for going into this pedagogically, I wrote most of this while I was working out for myself what was going on, and hopefully this sill be a good explanation for people who stumble across this in the future. We're dealing with Generators, Iterators and Iterables here. A Generator is weird: Iterators in general should not 'hold things' (like locks, open files or IO wrappers), because python gives them no way to clean up. If an iterator does need to hold something, then it should really be a generator, which has the additional 'infrastructure' of Currently, If we want the progress bar to be able to catch For a toy example:
This does work as expected!
There is one downside of this, which is that the iteration in the It might be worth discussing moving the state for the progress bar into the generator object, and leaving |
Thank you for writing this pedagogically! |
I realized that we could do a less invasive job by promoting the ProgressBar itself to being a Generator. This is a much smaller change, as a Generator is just a special type of Iterator, which the ProgressBar is already. It also means the current examples and code usage can stay identical, and that we aren't introducing any new objects. It took me a little while to figure out how to arrange for python to run With that, whenever the progress bar is garbage collected, it makes a direct call to |
This is what I eventually did in my project using ProgressBar: def progress_bar(iterator, *args, **kwargs):
with progressbar.ProgressBar(*args, **kwargs) as progress:
for item in progress(iterator):
yield item Which is very close to what |
The above (and the shortcut) both do something similar but not identical to the solution in the PR.
This is different to the solution in the linked PR, which is to make the |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
When redirect_stdout is beign used, and the iterator is interrupted, for example by a KeyboardInterrupt, stdout remains wrapped,
Example code
You'll end up with the 50% completed progress bar sitting on your terminal and refusing to leave.
When an exception stops the progress of the iterator, the progress bar doesn't take notice and unwrap stdout, as it does when finished() is called.
Manually wrapping the iteration in a try:except: works, but obviously isn't very nice
Versions
Python 3.7.3, IPython 7.8.0, Linux, progressbar version 3.47.0
The text was updated successfully, but these errors were encountered: