Repository navigation
should not import optional dependencies until actually necessary #176
Description
Activity
- added a commit that references this issue
on Jun 2, 2016 We 100% agree, but this is just how Python is designed: all imports in imported submodules in
__init__are executed when you importtqdm, whether or not you need them for the submodule you use...Maybe we can get around this issue by replacing static imports by dynamic imports in
__init__, but I'm not sure this will be standard nor very compatible... We need to dig deeper into this issue sincetqdmis becoming highly modular.- added a commit that references this issue
on Jun 2, 2016 well -- that is the beauty of Python that it is so dynamic allowing for all kinds of wizardry (e.g. imports within functions, patching of the namespaces, etc ;-) ). E.g. see how I had to workaround (somewhat quick and dirty) this issue for ourselves: datalad/datalad@81e6113 which boils to delaying import of our progressbar adapters until they are actually used for the first time.
In your case, I think ideal most Pythonic solution IMHO would have been not to dump everything into the top level API (i.e.
__init__.py) and require something likefrom tqdm.ipython import tqdm_notebook. But if you are to stay with top level API providing all those, you could easily do it e.g. via somewhat ugly adapters #177also not sure really if
tqdm.tqdm_notebookis better than what could be more descriptive and avoiding c-style prefixingtqdm.ipython.notebook(if you do decide to change the API) ;-)I don't think changing the API would be better, as this would greatly reduce the ergonomics of
tqdm. Your solution isn't that bad, thank you very much for the suggestion! An adapter may be the way to go here. Or lazy imports like with this library./EDIT: tried it, seems to be a very good implementation of delayed imports in Python, but it does not support relative imports, so it doesn't work with
tqdmfor our purpose... Also, I'm not sure it works with Python 3, I guess it needs some update.currently https://github.com/tqdm/tqdm/tree/lazydoc doesn't quite do it (thanks @yarikoptic for the suggestion)...
tqdm.tqdm_notebook.__doc__is accessible, but>>> help(tqdm.tqdm_notebook)won't pass that docstring through...d'oh -- my ipython rotten soul forgot about pyhelp... indeed -- that one seems to be too smart for its own good. FWIW I have tried to see if we could trick it but unfortunately didn't find any easy way
Sorry guys I'm a bit silent but I am really busy for the next two weeks so I can't contribute on this issue atm, but I'll check it out as soon as I'm out of the water with work.
Found another issue with current solution for
tqdm_notebookusing a delayed adapter: class methods just don't work, for exampletqdm_notebook.write("hello")outputs the following error:AttributeError: 'function' object has no attribute 'write'See #188.
So maybe we should just scrap the
__all__in__init__.pyand reorganize the wholetqdmlib. Here is a suggestion from @wernight in #188:# Do one of: import tqdm.console as tqdm import tqdm.gui as tqdm import tqdm.notebook as tqdm # All have same interface: tqdm.trange(...) tqdm.tqdm(...) tqdm.write(...)If we want to provide something similar to the old interface, we could also do with the same architecture:
from tqdm.console import tqdm, trange for i in trange(10): etc.What do you think guys? Should we continue with delayed imports or just reorganize
tqdmin a more modular fashion? (of course, in the latter case, we would break the API, so we would need to release a major release...).Reacted by Werner BerouxAn alternative to doing a full architecture reorganization, while keeping
__all__in__init__.py: we could make it standard that a wrapper function needs to be called to fetch the target tqdm class (code not tested):# in __init__.py def tqdm_load(): from tqdm import tqdm return tqdm # then in any script from tqdm import tqdm_load tqdm_class = tqdm_load() t = tqdm_class() tqdm_class.write("hello") t.write("hello")Pro is that we retain all features and a pretty much similar API to what we have now but class methods and all functionalities should work as expected, con is obviously that it's quite non-pythonic and ugly to use.
- added a commit that references this issue
on Oct 31, 2016 Note: language-level lazy imports PEP#0690 land in Python 3.12 🤞
while troubleshooting some awkward side effect of my app failing as far as I import tqdm, I discovered that tqdm unconditionally imports ipython (and probably other functionality if present, such as pandas) even if I have no intent on using it. It adds quite quite an overhead to the import, e.g.
with ipython installed/available
without:
i.e. having ipython available contributes now almost 300% penalty
I guess ideally all those imports should happen only if related functionality is requested