Description: When using tqdm_ray.tqdm within an IPython or Jupyter environment, an AttributeError: 'NoneType' object has no attribute 'outputs' is consistently raised and ignored (as an Exception ignored in:) during program shutdown or kernel teardown. This occurs even when the primary code execution completes successfully without any other errors.
The issue specifically points to IPython.core.interactiveshell.py within the tqdm traceback, suggesting a conflict or race condition in how tqdm_ray attempts to finalize its display when the interactive shell’s output streams are no longer valid or are being de-initialized.
This error does not occur when the same code is run directly via python your_script.py from a standard terminal, indicating it’s an environment-specific cleanup issue rather than a core functional bug in the user’s code or tqdm_ray’s primary operation.
Steps to Reproduce:
-
Launch an IPython console or a Jupyter Notebook.
-
Run the following Minimal Reproducible Example (MRE) in a cell:
— Start Minimal Reproducible Example (MRE) —
from ray.experimental import tqdm_ray
import timeprint(“Starting loop…”)
This loop demonstrates the basic usage that triggers the issue on cleanup
for i in tqdm_ray.tqdm(range(10)):
time.sleep(0.1) # Simulate some work
print(“Loop finished.”)— End Minimal Reproducible Example (MRE) —
-
Observe the output after the loop completes and the cell finishes execution.
Expected Behavior: The code should execute, the progress bar should display, and upon completion, no error traceback should be printed. The program should terminate cleanly.
Actual Behavior: The loop executes, the progress bar displays correctly, and “Loop finished.” is printed. However, immediately after the program effectively ends, an Exception ignored in: traceback appears, leading to AttributeError: 'NoneType' object has no attribute 'outputs' originating from tqdm/std.py and IPython/core/interactiveshell.py.
Workaround: The issue can be prevented by explicitly calling .close() on the tqdm_ray object after the loop completes. Using a with statement also effectively resolves it.
Example of workaround:
from ray.experimental import tqdm_ray
import time
print("Starting loop with explicit close...")
pbar = tqdm_ray.tqdm(range(10))
for i in pbar:
time.sleep(0.1)
pbar.close() # Explicitly close the progress bar
print("Loop finished cleanly.")