GZipResponder has been rewritten so that it no longer throws not raised exception warning#2869
GZipResponder has been rewritten so that it no longer throws not raised exception warning#2869nesb1 wants to merge 1 commit intoKludex:masterfrom
GZipResponder has been rewritten so that it no longer throws not raised exception warning#2869Conversation
…gs like `Exception ignored in: <gzip on 0x7f0fd0276380>`
If you follow the linked issues/PRs, you'll see on the CPython issue, Thomas said that we solved in Starlette. It was solved on #2662. |
|
I guess you are using an old version of Starlette? Please share the whole traceback instead of only the gzip module part... |
|
Closing this PR since the user didn't share a way to reproduce, nor the package versions, nor marked the PR checklist. Please create a discussion or reply here with the missing information, and we can reopen. |
|
@Kludex you can copy my test to reproduce this issue on master and python 3.13.1. |
|
@Kludex The difficulty lies in the fact that I cannot provide a detailed traceback; all I have is a trace from the gzip module. Unraised Exceptions do not have a detailed description of the call stack, as the problem occurs at the moment the garbage collector begins its work, and it can start at any time. If you try to print the current stack before the garbage collector starts, there will be calls unrelated to the problem. |
|
Please provided an MRE. |
MRE is an unit test in this mr, this test fails on master, but works with my changes |
|
That's not an MRE. |
EnvironmentPython 3.13.1 CodeActual output:Expected output:no warnings are expected in stdout |
|
Why would you use This doesn't reproduce: from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.middleware.gzip import GZipMiddleware
from starlette.requests import Request
from starlette.responses import PlainTextResponse
from starlette.routing import Route
async def homepage(request: Request) -> PlainTextResponse:
return PlainTextResponse("Hello, world" * 100)
app = Starlette(routes=[Route("/", homepage)], middleware=[Middleware(GZipMiddleware)]) |
|
@Kludex I have also made progress in studying this issue, and I am ready to provide a higher-level example: from asyncio import CancelledError
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.middleware.gzip import GZipMiddleware, GZipResponder
from starlette.requests import Request
from starlette.responses import PlainTextResponse
from starlette.routing import Route
from starlette.testclient import TestClient
async def homepage(request: Request) -> PlainTextResponse:
return PlainTextResponse("Hello, world" * 100)
def gzip_responder_call_with_cancelled_error(*args, **kwargs):
raise CancelledError()
GZipResponder.__call__ = gzip_responder_call_with_cancelled_error
app = Starlette(routes=[Route("/", homepage)], middleware=[Middleware(GZipMiddleware)])
test_client: TestClient = TestClient(
app, raise_server_exceptions=False
)
test_client.get("/", headers={"accept-encoding": "gzip"})As I mentioned earlier, the problem is reproducible if an instance of |
|
@Kludex I think it should be reopened, as it is relevant. |
|
I don't seem to be able to reopen this PR. Can you create an issue, please? I'll investigate when I have time. |
Summary
Hello, thank you to everyone involved for this wonderful project. I'm glad to have the opportunity to contribute in some way.
I'm using
FastAPIin my web service, and after upgrading toPython 3.13, I've noticed a large number of warnings like this:I spent a considerable amount of time trying to understand where this error actually comes from and realized that it's related to
GzipMiddleware. I saw the issue #2615, but honestly, I didn't understand why it was marked as completed.This error occurs because the
BytesIOobject is closed before theGzipFile. I suggest using these two objects through a context manager, as mentioned in theCPythonissue python/cpython#122727.I also spent a lot of time writing a test for this, so let me explain it. I couldn't write the test similarly to other tests in
gzip_middleware, where requests are made through the test client; for some reason, the issue would not reproduce this way, possibly due to garbage collection peculiarities. However, in the current test, it's evident that the problem reproduces quite easily—one only needs to create aGzipResponderobject and delete it. The test was written before I fixed the implementation, and I confirmed that it indeed did not work.Checklist