fix nested `asyncio`, document async `break` hazard

- fixes #1074
This commit is contained in:
Casper da Costa-Luis 2020-11-20 23:27:22 +00:00
parent b80490e12c
commit ee5f8d21e8
No known key found for this signature in database
GPG Key ID: 986B408043AE090D
4 changed files with 81 additions and 10 deletions

View File

@ -744,6 +744,31 @@ custom callback take advantage of this, simply use the return value of
external_callback(**self.format_dict)
return displayed
``asyncio``
~~~~~~~~~~~
Note that ``break`` isn't currently caught by asynchronous iterators.
This means that ``tqdm`` cannot clean up after itself in this case:
.. code:: python
from tqdm.asyncio import tqdm
async for i in tqdm(range(9)):
if i == 2:
break
Instead, either call ``pbar.close()`` manually or use the context manager syntax:
.. code:: python
from tqdm.asyncio import tqdm
with tqdm(range(9)) as pbar:
async for i in pbar:
if i == 2:
break
Pandas Integration
~~~~~~~~~~~~~~~~~~

View File

@ -961,6 +961,31 @@ custom callback take advantage of this, simply use the return value of
external_callback(**self.format_dict)
return displayed
``asyncio``
~~~~~~~~~~~
Note that ``break`` isn't currently caught by asynchronous iterators.
This means that ``tqdm`` cannot clean up after itself in this case:
.. code:: python
from tqdm.asyncio import tqdm
async for i in tqdm(range(9)):
if i == 2:
break
Instead, either call ``pbar.close()`` manually or use the context manager syntax:
.. code:: python
from tqdm.asyncio import tqdm
with tqdm(range(9)) as pbar:
async for i in pbar:
if i == 2:
break
Pandas Integration
~~~~~~~~~~~~~~~~~~

View File

@ -14,8 +14,8 @@ as_completed = partial(tqdm_asyncio.as_completed, miniters=0, mininterval=0)
def with_setup_sync(func):
@wraps(func)
def inner():
return asyncio.run(func())
def inner(*args, **kwargs):
return asyncio.run(func(*args, **kwargs))
return inner
@ -35,20 +35,21 @@ async def acount(*args, **kwargs):
@with_setup_sync
async def test_generators():
async def test_generators(capsys):
"""Test asyncio generators"""
with closing(StringIO()) as our_file:
async for i in tqdm(count(), desc="counter", file=our_file):
with tqdm(count(), desc="counter") as pbar:
async for i in pbar:
if i >= 8:
break
assert '9it' in our_file.getvalue()
our_file.seek(0)
our_file.truncate()
_, err = capsys.readouterr()
assert '9it' in err
async for i in tqdm(acount(), desc="async_counter", file=our_file):
with tqdm(acount(), desc="async_counter") as pbar:
async for i in pbar:
if i >= 8:
break
assert '9it' in our_file.getvalue()
_, err = capsys.readouterr()
assert '9it' in err
@with_setup_sync

View File

@ -62,6 +62,26 @@ class tqdm_asyncio(std_tqdm):
yield from cls(asyncio.as_completed(fs, loop=loop, timeout=timeout),
total=total, **tqdm_kwargs)
def __new__(cls, *args, **kwargs):
"""
Workaround for mixed-class same-stream nested progressbars.
See [#509](https://github.com/tqdm/tqdm/issues/509)
"""
with cls.get_lock():
try:
cls._instances = std_tqdm._instances
except AttributeError:
pass
instance = super(tqdm_asyncio, cls).__new__(cls, *args, **kwargs)
with cls.get_lock():
try:
# `std_tqdm` may have been changed so update
cls._instances.update(std_tqdm._instances)
except AttributeError:
pass
std_tqdm._instances = cls._instances
return instance
def tarange(*args, **kwargs):
"""