Repository: spyder-ide/spyder

Issue:
Invoking `warnings.simplefilter` in the console results in an exception
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

### Issue Report Checklist

* [X] Searched the [issues page](https://github.com/spyder-ide/spyder/issues?q=is%3Aissue) for similar reports
* [X] Read the relevant sections of the [Spyder Troubleshooting Guide](https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ) and followed its advice
* [X] Reproduced the issue after updating with ``conda update spyder`` (or ``pip``, if not using Anaconda)
* [X] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [X] Tried basic troubleshooting (if a bug/error)
    * [X] Restarted Spyder
    * [ ] Reset preferences with ``spyder --reset``
    * [ ] Reinstalled the latest version of [Anaconda](https://www.anaconda.com/download/)
    * [ ] Tried the other applicable steps from the Troubleshooting Guide
* [X] Completed the **Problem Description**, **Steps to Reproduce** and **Version** sections below


## Problem Description

Trying to use `warning.simplefilter` from the console results in an exception.

### What steps reproduce the problem?

1.  Start spyder
2. Write in the console `import warnings` and then `warnings.simplefilter('error')` 

### What is the expected output? What do you see instead?

I would expect that to just go through as it does in jupyter qtconsole.

However, you get an `exception ignored`

### Paste Traceback/Error Below (if applicable)
<!--- Copy from error dialog or View > Panes > Internal Console --->

```python-traceback
 Exception ignored in: <function Socket.__del__ at 0x7f740e478400>
Traceback (most recent call last):
  File "/home/callegar/PythonEnvs/Py3.11-devel/lib/python3.11/site-packages/zmq/sugar/socket.py", line 182, in __del__
    warn(
ResourceWarning: Unclosed socket <zmq.Socket(zmq.PUSH) at 0x7f73ee1246e0>
```

## Versions
<!--- You can get this information from Help > About Spyder...
or (if Spyder won't launch) the "conda list" command
from the Anaconda Prompt/Terminal/command line. --->

* Spyder version: 5.4.3  (pip)
* Python version: 3.11.3 64-bit
* Qt version: 5.15.2
* PyQt5 version: 5.15.9
* Operating System: Linux 6.3.5-2-MANJARO

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
# Mandatory:
atomicwrites >=1.2.0                             :  1.4.1 (OK)
chardet >=2.0.0                                  :  5.1.0 (OK)
cloudpickle >=0.5.0                              :  2.2.1 (OK)
cookiecutter >=1.6.0                             :  2.1.1 (OK)
diff_match_patch >=20181111                      :  20230430 (OK)
intervaltree >=3.0.2                             :  3.1.0 (OK)
IPython >=7.31.1,<9.0.0,!=8.8.0,!=8.9.0,!=8.10.0 :  8.14.0 (OK)
jedi >=0.17.2,<0.19.0                            :  0.18.2 (OK)
jellyfish >=0.7                                  :  0.11.2 (OK)
jsonschema >=3.2.0                               :  4.17.3 (OK)
keyring >=17.0.0                                 :  23.13.1 (OK)
nbconvert >=4.0                                  :  7.4.0 (OK)
numpydoc >=0.6.0                                 :  1.5.0 (OK)
parso >=0.7.0,<0.9.0                             :  0.8.3 (OK)
pexpect >=4.4.0                                  :  4.8.0 (OK)
pickleshare >=0.4                                :  0.7.5 (OK)
psutil >=5.3                                     :  5.9.5 (OK)
pygments >=2.0                                   :  2.15.1 (OK)
pylint >=2.5.0,<3.0                              :  2.17.4 (OK)
pylint_venv >=2.1.1                              :  3.0.1 (OK)
pyls_spyder >=0.4.0                              :  0.4.0 (OK)
pylsp >=1.7.2,<1.8.0                             :  1.7.3 (OK)
pylsp_black >=1.2.0                              :  1.3.0 (OK)
qdarkstyle >=3.0.2,<3.2.0                        :  3.1 (OK)
qstylizer >=0.2.2                                :  0.2.2 (OK)
qtawesome >=1.2.1                                :  1.2.3 (OK)
qtconsole >=5.4.2,<5.5.0                         :  5.4.3 (OK)
qtpy >=2.1.0                                     :  2.3.1 (OK)
rtree >=0.9.7                                    :  1.0.1 (OK)
setuptools >=49.6.0                              :  67.8.0 (OK)
sphinx >=0.6.6                                   :  7.0.1 (OK)
spyder_kernels >=2.4.3,<2.5.0                    :  2.4.3 (OK)
textdistance >=4.2.0                             :  4.5.0 (OK)
three_merge >=0.1.1                              :  0.1.1 (OK)
watchdog >=0.10.3                                :  3.0.0 (OK)
xdg >=0.26                                       :  0.28 (OK)
zmq >=22.1.0                                     :  25.1.0 (OK)

# Optional:
cython >=0.21                                    :  0.29.35 (OK)
matplotlib >=3.0.0                               :  3.7.1 (OK)
numpy >=1.7                                      :  1.24.3 (OK)
pandas >=1.1.1                                   :  2.0.2 (OK)
scipy >=0.17.0                                   :  1.10.1 (OK)
sympy >=0.7.3                                    :  1.12 (OK)
```



Discussion:
Hey @callegar, thanks for reporting. I was able to easily reproduce your error with the provided instructions.

Since this comes directly from PyZMQ, I'd like to ask @minrk what we could do about it. As extra info, this doesn't happen in QtConsole (as @callegar mentioned too).
Ultimately, this is an issue in ipykernel.

This is a warning from pyzmq, when a Socket is disposed of via `__del__` without closing it explicitly (Python does the same for files, for example).

I tracked it down to ipykernel's [event pipe](https://github.com/ipython/ipykernel/blob/1c7f626f801168293115c7343b61a21b5fa8f9e7/ipykernel/iostream.py#L92-L106), which uses thread local storage for PUSH sockets to send events to the IO thread. So when a thread is destroyed, the local PUSH socket is also destroyed, implicitly closing it, triggering this warning.

I'll need to think about how best to handle that, because he thread local lifetime is super handy, but I don't know how to efficiently close sockets when threads close because there [isn't an 'on_close' hook](https://github.com/python/cpython/issues/58281). So we'd have to implement our own garbage collection of these per-thread sockets.

You can reproduce it in qtconsole or a notebook by launching a thread that prints:

```python
from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor() as pool:
    pool.submit(print, 5)
```

because this will happen when a thread has printed (or called sys.stdout.flush or interacted with the IOPubThread).
Thanks for investigating the issue and finding the underlying reason.
Are you going to manage this or should i open an issue on ipykernel myself?
Patch submitted to ipykernel at https://github.com/ipython/ipykernel/pull/1125
It may be worth tracking down exactly what the spyder kernel's doing that's starting and terminating a thread on every execution, because that's the _direct_ cause of why this is unique to Spyder, even though doing so shouldn't create any of these warnings.
Ha! I think I tracked it down, and it's me again. Spyder enables [wurlitzer](https://github.com/minrk/wurlitzer) as an IPython extension, which runs a thread to pipe output and cleans up the thread on each execution. You might want to skip this, because ipykernel 6 introduces this same feature as default behavior (made optional in 6.3.0 via [ IPKernelApp.capture_fd_output](https://github.com/ipython/ipykernel/blob/v6.3.0/CHANGELOG.md) so it can be opt-out, but still on by default).
Thanks Min for the quick response! You said:

> Spyder enables [wurlitzer](https://github.com/minrk/wurlitzer) as an IPython extension, which runs a thread to pipe output and cleans up the thread on each execution. You might want to skip this, because ipykernel 6 introduces this same feature as default behavior

I thought Wurlitzer was more robust than `capture_fd_output` (there were [some issues](https://github.com/ipython/ipykernel/issues/859) with the later until recently).

So, your recommendation is to go the other way around now?
I have mixed feelings about it! I do think the approach taken in wurlitzer is a little bit more robust. But I _believe_ most of the issues in capture_fd_output have been resolved, though quite recently if you'd like to wait a while. I don't think there's any rush. I do think enough folks are using ipykernel's default behavior that most issues will get caught and fixed.

In both cases, large output can still cause hangs until one or both switches to using files, as described [here](https://github.com/minrk/wurlitzer/issues/48#issuecomment-905263154).
> I have mixed feelings about it!

Haha, ok.

> I do think enough folks are using ipykernel's default behavior that most issues will get caught and fixed.

Ok, that's a very good point. Thanks for the insight Min!

> But I believe most of the issues in capture_fd_output have been resolved, though quite recently if you'd like to wait a while. I don't think there's any rush.

That's a good point too. We can wait for a couple more months before switching to `capture_fd_output` then.

Resolving patch:
diff --git a/external-deps/spyder-kernels/setup.py b/external-deps/spyder-kernels/setup.py
--- a/external-deps/spyder-kernels/setup.py
+++ b/external-deps/spyder-kernels/setup.py
@@ -40,7 +40,7 @@ def get_version(module='spyder_kernels'):
     'backports.functools-lru-cache; python_version<"3"',
     'cloudpickle',
     'ipykernel>=4.5,<5; python_version<"3"',
-    'ipykernel>=6.16.1,<7; python_version>="3"',
+    'ipykernel>=6.23.2,<7; python_version>="3"',
     'ipython<6; python_version<"3"',
     'ipython>=7.31.1,<9,!=8.8.0,!=8.9.0,!=8.10.0,!=8.11.0,!=8.12.0,!=8.12.1; python_version>="3"',
     'jupyter-client>=5.3.4,<6; python_version<"3"',


Test patch: