Comments (6)
irc main [5] 🐚 env PYTHONTRACEMALLOC=20 .tox/py/bin/pytest -p no:cov -p no:mypy -p no:ruff -k reconnects
=============================================================== test session starts ===============================================================
platform darwin -- Python 3.12.4, pytest-8.2.2, pluggy-1.5.0
rootdir: /Users/jaraco/code/jaraco/irc
configfile: pytest.ini
plugins: typeguard-4.3.0, checkdocs-2.13.0, enabler-3.1.1
collected 36 items / 35 deselected / 1 selected
irc/tests/test_bot.py . [100%]
================================================================ warnings summary =================================================================
irc/tests/test_bot.py::TestBot::test_reconnects_are_stable
/Users/jaraco/code/jaraco/irc/irc/tests/test_bot.py:139: ResourceWarning: unclosed <socket.socket fd=14, family=2, type=1, proto=0, laddr=('127.0.0.1', 64398)>
bot.reactor.process_once()
Object allocated at:
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_callers.py", line 103
res = hook_impl.function(*args)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/main.py", line 364
item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_hooks.py", line 513
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_manager.py", line 120
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_callers.py", line 103
res = hook_impl.function(*args)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 116
runtestprotocol(item, nextitem=nextitem)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 135
reports.append(call_and_report(item, "call", log))
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 240
call = CallInfo.from_call(
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 341
result: Optional[TResult] = func()
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 241
lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_hooks.py", line 513
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_manager.py", line 120
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_callers.py", line 103
res = hook_impl.function(*args)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 173
item.runtest()
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/python.py", line 1632
self.ihook.pytest_pyfunc_call(pyfuncitem=self)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_hooks.py", line 513
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_manager.py", line 120
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_callers.py", line 103
res = hook_impl.function(*args)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/python.py", line 162
result = testfunction(**testargs)
File "/Users/jaraco/code/jaraco/irc/irc/tests/test_bot.py", line 139
bot.reactor.process_once()
irc/tests/test_bot.py::TestBot::test_reconnects_are_stable
/Users/jaraco/code/jaraco/irc/irc/tests/test_bot.py:139: ResourceWarning: unclosed <socket.socket fd=14, family=2, type=1, proto=0, laddr=('127.0.0.1', 64399)>
bot.reactor.process_once()
Object allocated at:
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_callers.py", line 103
res = hook_impl.function(*args)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/main.py", line 364
item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_hooks.py", line 513
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_manager.py", line 120
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_callers.py", line 103
res = hook_impl.function(*args)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 116
runtestprotocol(item, nextitem=nextitem)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 135
reports.append(call_and_report(item, "call", log))
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 240
call = CallInfo.from_call(
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 341
result: Optional[TResult] = func()
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 241
lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_hooks.py", line 513
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_manager.py", line 120
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_callers.py", line 103
res = hook_impl.function(*args)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/runner.py", line 173
item.runtest()
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/python.py", line 1632
self.ihook.pytest_pyfunc_call(pyfuncitem=self)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_hooks.py", line 513
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_manager.py", line 120
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/pluggy/_callers.py", line 103
res = hook_impl.function(*args)
File "/Users/jaraco/code/jaraco/irc/.tox/py/lib/python3.12/site-packages/_pytest/python.py", line 162
result = testfunction(**testargs)
File "/Users/jaraco/code/jaraco/irc/irc/tests/test_bot.py", line 139
bot.reactor.process_once()
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================================== 1 passed, 35 deselected, 2 warnings in 5.12s ===================================================
from irc.
I tried adding a disconnect at the end.
diff --git a/irc/tests/test_bot.py b/irc/tests/test_bot.py
index 213eca3..c91a897 100644
--- a/irc/tests/test_bot.py
+++ b/irc/tests/test_bot.py
@@ -139,6 +139,7 @@ class TestBot:
bot.reactor.process_once()
time.sleep(0.01)
assert len(bot.reactor.scheduler.queue) <= 1
+ bot.disconnect()
def test_version():
But that made matters worse:
=============================================================== test session starts ===============================================================
platform darwin -- Python 3.12.4, pytest-8.2.2, pluggy-1.5.0
rootdir: /Users/jaraco/code/jaraco/irc
configfile: pytest.ini
plugins: typeguard-4.3.0, checkdocs-2.13.0, enabler-3.1.1
collected 36 items / 35 deselected / 1 selected
irc/tests/test_bot.py . [100%]
================================================================ warnings summary =================================================================
irc/tests/test_bot.py::TestBot::test_reconnects_are_stable
/Users/jaraco/code/jaraco/irc/irc/tests/test_bot.py:139: ResourceWarning: unclosed <socket.socket fd=14, family=2, type=1, proto=0, laddr=('127.0.0.1', 64871)>
bot.reactor.process_once()
Enable tracemalloc to get traceback where the object was allocated.
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
irc/tests/test_bot.py::TestBot::test_reconnects_are_stable
/Users/jaraco/code/jaraco/irc/irc/tests/test_bot.py:139: ResourceWarning: unclosed <socket.socket fd=14, family=2, type=1, proto=0, laddr=('127.0.0.1', 64872)>
bot.reactor.process_once()
Enable tracemalloc to get traceback where the object was allocated.
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
irc/tests/test_bot.py::TestBot::test_reconnects_are_stable
/Users/jaraco/code/jaraco/irc/irc/client.py:542: ResourceWarning: unclosed <socket.socket fd=15, family=2, type=1, proto=0, laddr=('127.0.0.1', 64873)>
del self.socket
Enable tracemalloc to get traceback where the object was allocated.
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================================== 1 passed, 35 deselected, 3 warnings in 0.64s ===================================================
from irc.
I managed to get a bit more detail about what's happening by passing --log-cli-level 0
.
------------------------------------------------------------------ live log call ------------------------------------------------------------------
DEBUG irc.client:client.py:164 connect(server='127.0.0.1', port=50516, nickname='reconnect_test', ...)
DEBUG irc.client:client.py:672 TO SERVER: NICK reconnect_test
DEBUG irc.client:client.py:672 TO SERVER: USER reconnect_test 0 * :reconnect_test
Level 8 irc.client:client.py:888 process_once()
Level 8 irc.client:client.py:854 process_data()
DEBUG irc.client:client.py:1218 _dispatcher: disconnect
Level 8 irc.client:client.py:888 process_once()
DEBUG irc.client:client.py:164 connect(server='127.0.0.1', port=50516, nickname='reconnect_test', ...)
DEBUG irc.client:client.py:672 TO SERVER: NICK reconnect_test
DEBUG irc.client:client.py:672 TO SERVER: USER reconnect_test 0 * :reconnect_test
Level 8 irc.client:client.py:888 process_once()
Level 8 irc.client:client.py:854 process_data()
DEBUG irc.client:client.py:1218 _dispatcher: disconnect
DEBUG irc.client:client.py:164 connect(server='127.0.0.1', port=50516, nickname='reconnect_test', ...)
DEBUG irc.client:client.py:672 TO SERVER: NICK reconnect_test
DEBUG irc.client:client.py:672 TO SERVER: USER reconnect_test 0 * :reconnect_test
Level 8 irc.client:client.py:888 process_once()
Level 8 irc.client:client.py:854 process_data()
DEBUG irc.client:client.py:1218 _dispatcher: disconnect
PASSED [100%]
from irc.
I suspect the issue lies in the Client.disconnect method:
Lines 523 to 543 in 2f6ba71
After learning a bit about the relationship between socket.shutdown and socket.close, I'm pretty sure the issue is that socket.close()
never gets called when the peer disconnected because self.quit()
fails or socket.shutdown
fails.
Indeed, applying the following diff, there are no more resource warnings:
diff --git a/irc/client.py b/irc/client.py
index 4d269a9..52262f3 100644
--- a/irc/client.py
+++ b/irc/client.py
@@ -532,13 +532,15 @@ class ServerConnection(Connection):
except AttributeError:
return
- self.quit(message)
+ # self.quit(message)
try:
self.socket.shutdown(socket.SHUT_WR)
- self.socket.close()
except OSError:
pass
+
+ self.socket.close()
+
del self.socket
self._handle_event(Event("disconnect", self.server, "", [message]))
from irc.
Oof. The Connection.quit
logic is tricky, because .quit
will call .disconnect
which calls .quit
. The only thing that prevents that from becoming an infinite loop is the check for self.connected
😬 .
from irc.
Oh! I don't need to be concerned about Connection.quit
for this issue. It didn't need to be commented out to address the warnings.
from irc.
Related Issues (20)
- After joining a channel, how do I get a list of usernames? HOT 1
- 'AioReactor' object has no attribute 'scheduler' HOT 3
- set_keepalive resulting into "irc.client.ServerNotConnectedError: Not connected."
- Empty quit message raises IndexError
- encoding outgoing messages seems to remove "\x1d" HOT 1
- Docs builds failing HOT 1
- IRCFoldedCase no longer folding HOT 1
- The addition of new numeric event names for SASL broke heisenbridge, which was using numeric codes. HOT 3
- SSL Support HOT 1
- `irc.connection.Factory.connect` should support `ssl.SSLContext.wrap_socket` with the `server_hostname` parameter HOT 1
- How to list channels HOT 2
- Error when attempting to join multiple channels HOT 2
- no colored or formatted text? HOT 5
- IRC Bot reconn strategy question HOT 3
- How to use data from one event handler in a different one? HOT 3
- Receive public messages HOT 1
- SASL example HOT 4
- 20.4.1 installs `docs` into site-packages HOT 2
- Add type annotations
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from irc.