Skip to content
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

deinit() doesn't work if init() was called twice. #145

Open
gilch opened this issue Sep 26, 2017 · 19 comments
Open

deinit() doesn't work if init() was called twice. #145

gilch opened this issue Sep 26, 2017 · 19 comments

Comments

@gilch
Copy link

gilch commented Sep 26, 2017

>>> import colorama
>>> import sys
>>> id(sys.stdout)
2198406407512
>>> colorama.init()
>>> id(sys.stdout)
2198419631912
>>> colorama.deinit()
>>> id(sys.stdout)  # back to the original, as expected
2198406407512
>>> colorama.init()
>>> colorama.init()
>>> colorama.deinit()
>>> id(sys.stdout)  # What?
2198419494224

I think init() should probably either raise an error, or no-op if colorama was already initialized.
But in any case, it should not break deinit by losing the original stdout/stderr.

@joshuawise610
Copy link

I oringinally thought that this problem could be solved by just running deinit() again (as init() was called twice therefore to go back would require two deinit() calls) to get back to the original stdout.

However this does not seem to be the case when I started investigating, I found out that the second deinit() does not have any affect on the output of stdout, however the first deinit() seems to have some effect and lets you go back to the stdout output after the first init() was called.

>>> import colorama
>>> import sys
>>> id(sys.stdout)  # The original stdout output
56145200
>>> colorama.init()
>>> id(sys.stdout)  # The stdout output after init()
94884112
>>> colorama.deinit()
>>> id(sys.stdout)  # Should be back to the original stdout output
56145200  # stdout goes back

>>> colorama.init()
>>> id(sys.stdout)  # The stdout output after init()
95230320
>>> colorama.init()  # init() for the second time
>>> id(sys.stdout)  # The stdout output after the second init()
95230544
>>> colorama.deinit()  # deinit() once
>>> id(sys.stdout)  # stdout output after first deinit()
95230320  # stdout goes back to stdout after first deinit()
>>> colorama.deinit() # deinit() again (second time), should go back to original stdout ouput
>>> id(sys.stdout)  # stdout output after second deinit()
95230320  # stdout output is the same after the second deinit() as after the first deinit()

For the curious, the same effect occurs when more calls to init() are made without calling deinit(). Calling init() 3 times in a row and then calling deinit() 3 times makes stdout print out the same result as after the first init() this implies that multiple init() calls have an effect on stderr while multiple deinit() calls have no effect on stderr after the first deinit() call was made.

I hope this helps, I think an error needs to be raised when init() is called again before deinit() is called to prevent this problem happening.

@tartley
Copy link
Owner

tartley commented Feb 21, 2018

If memory serves, init() uses static variables to store the original stdout/stderr, so calling it twice really does overwrite and lose the original.

@pslacerda
Copy link

I'm worried about calling init(), someone could already called it before. So I want to fix this issue.

Should reinit() be dropped or deprecated?

@AlkisPis
Copy link

To @gilch, Sep 26, 2017

  1. I have checked id(sys.stdout) before init() and after deinit() and indeed, they are the same as in your code. Yet, regular printing is not restored. The text colors and style set with the last 'colorama' call still work!
  2. So, what is your solution for making deinit() work?

@tartley
Copy link
Owner

tartley commented Nov 11, 2019

@AlkisPis Play nice, m'kay? Glitch and everyone else are doing their best, giving time and effort for free, we should all be grateful, not demanding.

I'll see if I can figure this out in the next few days. Hugs, all

@tartley
Copy link
Owner

tartley commented Nov 11, 2019

I'm thinking of fixing this by making 'init()' a no-op if it has already wrapped stdout. This has some precedence, because 'init()' is already a no-op in other situations, such as on non-windows platforms. So we'll only need a single 'deinit()' to fix multiple 'init()' calls.

@tartley
Copy link
Owner

tartley commented Nov 11, 2019

Also, @AlkisPis, the above means that text colors and style will not be reset to regular on calling 'deinit()'. Calling 'deinit' never does this, no matter whether 'init' was called twice or just once. If an application wants them reset, it should print an ANSI 'reset' code, e.g. by printing Colorama's Style.RESET_ALL, before calling 'deinit()'.

@pslacerda
Copy link

pslacerda commented Nov 11, 2019

I used colorama to pretty log and was very cool to have multi-platform support. Hope to use it more times in the future.

I liked the idea of init became no-op, the user interface would be very clean, @tartley.

Another option would be to wrap stdout and keep a reference on stdout.__colorama_original_stdout. Init and deinit would call hasattr(stdout, '__colorama_original_stdout') it being lazy initialized or explicitly. Seems that it would avoid recursion errors.

@tartley
Copy link
Owner

tartley commented Nov 11, 2019

Yuck, this code I wrote is rubbish. Sorry people. :-) Upvotes on this comment are acceptable.

@tartley
Copy link
Owner

tartley commented Nov 11, 2019

There is a complication.

Current behavior is that calling 'init' more than once, besides breaking 'deinit', can also override the passed values of kwargs. (autoreset, convert, strip, wrap)

So simply making the 2nd 'init' a no-op would break this existing behavior. I'll see if I can fix the issue while preserving this behavior...

@tartley
Copy link
Owner

tartley commented Nov 11, 2019

Can someone with a Windows machine try out the branch above? Run tests and review the changes? Many thanks.

@pslacerda
Copy link

For me seems alright but no Windows around here either.

@AlkisPis
Copy link

AlkisPis commented Nov 12, 2019

@AlkisPis Play nice, m'kay? Glitch and everyone else are doing their best, giving time and effort for free, we should all be grateful, not demanding.

Why am I not playing nice? Anyway, this is an opportunity for me to thank you for your nice package! :)

@AlkisPis
Copy link

Can someone with a Windows machine try out the branch above? Run tests and review the changes? Many thanks.

@tartley, I have a Windows OS. What "branch" exactly to test? I visited #236 but it's a confusion (for me). Can you just write the changes that must be done to 'initialise.py'?

FYI, as it is now, if I call init(() once and then deinit(), the initial stdout ID is restored. But if I call init(() twice, then whatever number of times I call deinit(), I get the ID I got after the first call to init(), never the initial ID (before the first call to init()).

@SamuelJansen
Copy link

SamuelJansen commented Jan 4, 2021

I oringinally thought that this problem could be solved by just running deinit() again (as init() was called twice therefore to go back would require two deinit() calls) to get back to the original stdout.

However this does not seem to be the case when I started investigating, I found out that the second deinit() does not have any affect on the output of stdout, however the first deinit() seems to have some effect and lets you go back to the stdout output after the first init() was called.

>>> import colorama
>>> import sys
>>> id(sys.stdout)  # The original stdout output
56145200
>>> colorama.init()
>>> id(sys.stdout)  # The stdout output after init()
94884112
>>> colorama.deinit()
>>> id(sys.stdout)  # Should be back to the original stdout output
56145200  # stdout goes back

>>> colorama.init()
>>> id(sys.stdout)  # The stdout output after init()
95230320
>>> colorama.init()  # init() for the second time
>>> id(sys.stdout)  # The stdout output after the second init()
95230544
>>> colorama.deinit()  # deinit() once
>>> id(sys.stdout)  # stdout output after first deinit()
95230320  # stdout goes back to stdout after first deinit()
>>> colorama.deinit() # deinit() again (second time), should go back to original stdout ouput
>>> id(sys.stdout)  # stdout output after second deinit()
95230320  # stdout output is the same after the second deinit() as after the first deinit()

For the curious, the same effect occurs when more calls to init() are made without calling deinit(). Calling init() 3 times in a row and then calling deinit() 3 times makes stdout print out the same result as after the first init() this implies that multiple init() calls have an effect on stderr while multiple deinit() calls have no effect on stderr after the first deinit() call was made.

I hope this helps, I think an error needs to be raised when init() is called again before deinit() is called to prevent this problem happening.

or just make a .deinit() call in .init() definition

Something lik this:

def init(*agrs, **kwargs) :
    deinit(*propper_args, **propper_kwargs)
    '''following
    init
    method
    implementation'''

@TheTechRobo
Copy link

@tartley, I have a Windows OS. What "branch" exactly to test? I visited #236 but it's a confusion (for me). Can you just write the changes that must be done to 'initialise.py'?

You test using the branch "multiple-init"

@VelpaChallenger
Copy link

I checked the related issues/PRs and I am interested in working on a new init for colorama that doesn't have the known problems of the current one (I am referring to the final comment in #262 ). My terminal application was slowing down a lot and I found out it was due to the multiple init calls and no deinit (I wasn't able to find such information online), so I'd like to contribute to help others avoid these problems.

I see the issues/PRs are still opened so I am assuming the feature hasn't been released yet, but I'd still like to ask to confirm. It's also been a couple of years so I'd like to make sure I am not missing anything. But so far my understanding is that the new init would run only once, and if the programmer inadvertently adds a second init, then it simply won't run. It will also not allow wrappers to restart values, for example colorama.init(autoreset=True) followed by colorama.init(autoreset=False) will still have the behavior of autoreset=True. deinit() will still be required to set the original stdout again, but just one will be enough to restore the original state.

Is that correct?

@tartley
Copy link
Owner

tartley commented May 8, 2024

@VelpaChallenger Be aware that there is already a new version of init, called just_fix_windows_console, as described here. It has a different name so as to not break the code of people who are depending on the current behavior of 'init'. Maybe that will do what you need? Certainly it handles the case that this issue is meant to be about, of multiple calls to 'init' making programs slower and not deinit-init-ing properly.

If that doesn't handle your case, then I'm not sure what to recommend. Feel free to discuss it here, but don't produce a big PR because it probably will not get merged. We don't have a lot of time for changes to Colorama these days. Hugs!

@VelpaChallenger
Copy link

@tartley Yes, that one works. In fact, it also solves the problem of slowing down the terminal at all. Even with just one use, I don't see the slightest slow down. Very kind of you! Thanks for the response and the help 😄 . Hugs!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants