Open KleinerNull opened 7 years ago
No matter how it would look like, I'm sure that we need to any way to manage contexts. The current logging-spinner has nothing about this at all.
One thing making me to consider is that logging-spinner's first purpose is to display spinners without introducing any third-party APIs. Applications don't have to depend on logging-spinner's own API, but a loose protocol of the user_waiting
extra field. However, context managers introduce its own new APIs.
Actually logging-spinner uses pyspin under the hood. Although it doesn't provide context managers, there's @make_spin
decorator to manage contexts.
I don't see any third party API introduction here. It is just a simple context manager, you can provide him additionally:
In [1]: class SpinManager:
...: def __init__(self, logger, start_msg, final_msg):
...: self.logger = logger
...: self.start_msg = start_msg
...: self.final_msg = final_msg
...: def __enter__(self):
...: self.logger.info(self.start_msg, extra={'user_waiting': True})
...: def __exit__(self, *args):
...: self.logger.info(self.final_msg, extra={'user_waiting': False})
...:
In [2]: from logging_spinner import SpinnerHandler
In [3]: import logging
In [4]: logger = logging.getLogger('manager')
In [5]: logger.setLevel(logging.INFO)
In [6]: logger.addHandler(SpinnerHandler())
In [7]: from time import sleep
In [8]: with SpinManager(logger, 'Loading', 'Done'):
...: sleep(1)
...:
⠏ Loading
Done
The whole purpose of context manager in python is to manage resources. Everything that has some kind of open-close or start-end procedures is suited perfect for this. Opening and automatically closing files, connect and disconnect to databases, creating and deleting of tmp files and dictionaries etc.
Creating takes one or two minutes, why not provide it from the beginning?
By the way controlling the spinner is also not that hard:
In [14]: class SpinController(SpinManager):
...: def start(self, msg):
...: self.logger.info(msg, extra={'user_waiting': True})
...: def stop(self, msg):
...: self.logger.info(msg, extra={'user_waiting': False})
In [16]: with SpinController(logger, 'Loading', 'Done') as spinner:
...: sleep(1)
...: spinner.stop('Halt!')
...: sleep(1)
...: spinner.start('Loading again.')
...: sleep(1)
...:
...:
Halt! # the first ⠏ Loading was overwritten by Halt, but it was there.
⠏ Loading again.
Done
The with statement or also called context manager is considered as very safe, clean and therefore pythonic!
Implementing a spinner through a context manager would provide a even better interface. Something like this for example:
So you could provide even more complex behaivor like stopping the spinner or change color or whatever.
For a simple spinner you could also provide this:
It is just a suggestion, because I really like the context manager interface, keeps the code cleaner and so on ;)