--- /dev/null
+import sys
+from typing import NoReturn
+
+from starlette.datastructures import Headers, MutableHeaders
+from starlette.types import ASGIApp, Message, Receive, Scope, Send
+
+if sys.version_info >= (3, 14): # pragma: no cover
+ from compression.zstd import ZstdCompressor
+else: # pragma: no cover
+ from backports.zstd import ZstdCompressor
+
+DEFAULT_EXCLUDED_CONTENT_TYPES = ("text/event-stream",)
+
+
+class ZstdMiddleware:
+ def __init__(self, app: ASGIApp, minimum_size: int = 500, compresslevel: int = 3) -> None:
+ self.app = app
+ self.minimum_size = minimum_size
+ self.compresslevel = compresslevel
+
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
+ if scope["type"] != "http": # pragma: no cover
+ await self.app(scope, receive, send)
+ return
+
+ headers = Headers(scope=scope)
+ responder: ASGIApp
+ if "zstd" in headers.get("Accept-Encoding", ""):
+ responder = ZstdResponder(self.app, self.minimum_size, compresslevel=self.compresslevel)
+ else:
+ responder = IdentityResponder(self.app, self.minimum_size)
+
+ await responder(scope, receive, send)
+
+
+class IdentityResponder:
+ content_encoding: str
+
+ def __init__(self, app: ASGIApp, minimum_size: int) -> None:
+ self.app = app
+ self.minimum_size = minimum_size
+ self.send: Send = unattached_send
+ self.initial_message: Message = {}
+ self.started = False
+ self.content_encoding_set = False
+ self.content_type_is_excluded = False
+
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
+ self.send = send
+ await self.app(scope, receive, self.send_with_compression)
+
+ async def send_with_compression(self, message: Message) -> None:
+ message_type = message["type"]
+ if message_type == "http.response.start":
+ # Don't send the initial message until we've determined how to
+ # modify the outgoing headers correctly.
+ self.initial_message = message
+ headers = Headers(raw=self.initial_message["headers"])
+ self.content_encoding_set = "content-encoding" in headers
+ self.content_type_is_excluded = headers.get("content-type", "").startswith(DEFAULT_EXCLUDED_CONTENT_TYPES)
+ elif message_type == "http.response.body" and (self.content_encoding_set or self.content_type_is_excluded):
+ if not self.started:
+ self.started = True
+ await self.send(self.initial_message)
+ await self.send(message)
+ elif message_type == "http.response.body" and not self.started:
+ self.started = True
+ body = message.get("body", b"")
+ more_body = message.get("more_body", False)
+ if len(body) < self.minimum_size and not more_body:
+ # Don't apply compression to small outgoing responses.
+ await self.send(self.initial_message)
+ await self.send(message)
+ elif not more_body:
+ # Standard response.
+ body = self.apply_compression(body, more_body=False)
+
+ headers = MutableHeaders(raw=self.initial_message["headers"])
+ headers.add_vary_header("Accept-Encoding")
+ if body != message["body"]:
+ headers["Content-Encoding"] = self.content_encoding
+ headers["Content-Length"] = str(len(body))
+ message["body"] = body
+
+ await self.send(self.initial_message)
+ await self.send(message)
+ else:
+ # Initial body in streaming response.
+ body = self.apply_compression(body, more_body=True)
+
+ headers = MutableHeaders(raw=self.initial_message["headers"])
+ headers.add_vary_header("Accept-Encoding")
+ if body != message["body"]:
+ headers["Content-Encoding"] = self.content_encoding
+ del headers["Content-Length"]
+ message["body"] = body
+
+ await self.send(self.initial_message)
+ await self.send(message)
+ elif message_type == "http.response.body":
+ # Remaining body in streaming response.
+ body = message.get("body", b"")
+ more_body = message.get("more_body", False)
+
+ message["body"] = self.apply_compression(body, more_body=more_body)
+
+ await self.send(message)
+ elif message_type == "http.response.pathsend": # pragma: no branch
+ # Don't apply Zstd to pathsend responses
+ await self.send(self.initial_message)
+ await self.send(message)
+
+ def apply_compression(self, body: bytes, *, more_body: bool) -> bytes:
+ """Apply compression on the response body.
+
+ If more_body is False, any compression file should be closed. If it
+ isn't, it won't be closed automatically until all background tasks
+ complete.
+ """
+ return body
+
+
+class ZstdResponder(IdentityResponder):
+ content_encoding = "zstd"
+
+ def __init__(self, app: ASGIApp, minimum_size: int, compresslevel: int = 3) -> None:
+ super().__init__(app, minimum_size)
+
+ self.compressor = ZstdCompressor(level=compresslevel)
+
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
+ await super().__call__(scope, receive, send)
+
+ def apply_compression(self, body: bytes, *, more_body: bool) -> bytes:
+ if more_body:
+ return self.compressor.compress(body, mode=ZstdCompressor.CONTINUE)
+ else:
+ return self.compressor.compress(body, mode=ZstdCompressor.FLUSH_FRAME)
+
+
+async def unattached_send(message: Message) -> NoReturn:
+ raise RuntimeError("send awaitable not set") # pragma: no cover
--- /dev/null
+from __future__ import annotations
+
+from pathlib import Path
+
+import pytest
+
+from starlette.applications import Starlette
+from starlette.middleware import Middleware
+from starlette.middleware.zstd import ZstdMiddleware
+from starlette.requests import Request
+from starlette.responses import ContentStream, FileResponse, PlainTextResponse, StreamingResponse
+from starlette.routing import Route
+from starlette.types import Message
+from tests.types import TestClientFactory
+
+
+def test_zstd_responses(test_client_factory: TestClientFactory) -> None:
+ def homepage(request: Request) -> PlainTextResponse:
+ return PlainTextResponse("x" * 4000, status_code=200)
+
+ app = Starlette(
+ routes=[Route("/", endpoint=homepage)],
+ middleware=[Middleware(ZstdMiddleware)],
+ )
+
+ client = test_client_factory(app)
+ response = client.get("/", headers={"accept-encoding": "zstd"})
+ assert response.status_code == 200
+ assert response.text == "x" * 4000
+ assert response.headers["Content-Encoding"] == "zstd"
+ assert response.headers["Vary"] == "Accept-Encoding"
+ assert int(response.headers["Content-Length"]) < 4000
+
+
+def test_zstd_not_in_accept_encoding(test_client_factory: TestClientFactory) -> None:
+ def homepage(request: Request) -> PlainTextResponse:
+ return PlainTextResponse("x" * 4000, status_code=200)
+
+ app = Starlette(
+ routes=[Route("/", endpoint=homepage)],
+ middleware=[Middleware(ZstdMiddleware)],
+ )
+
+ client = test_client_factory(app)
+ response = client.get("/", headers={"accept-encoding": "identity"})
+ assert response.status_code == 200
+ assert response.text == "x" * 4000
+ assert "Content-Encoding" not in response.headers
+ assert response.headers["Vary"] == "Accept-Encoding"
+ assert int(response.headers["Content-Length"]) == 4000
+
+
+def test_zstd_ignored_for_small_responses(
+ test_client_factory: TestClientFactory,
+) -> None:
+ def homepage(request: Request) -> PlainTextResponse:
+ return PlainTextResponse("OK", status_code=200)
+
+ app = Starlette(
+ routes=[Route("/", endpoint=homepage)],
+ middleware=[Middleware(ZstdMiddleware)],
+ )
+
+ client = test_client_factory(app)
+ response = client.get("/", headers={"accept-encoding": "zstd"})
+ assert response.status_code == 200
+ assert response.text == "OK"
+ assert "Content-Encoding" not in response.headers
+ assert "Vary" not in response.headers
+ assert int(response.headers["Content-Length"]) == 2
+
+
+def test_zstd_streaming_response(test_client_factory: TestClientFactory) -> None:
+ def homepage(request: Request) -> StreamingResponse:
+ async def generator(bytes: bytes, count: int) -> ContentStream:
+ for index in range(count):
+ yield bytes
+
+ streaming = generator(bytes=b"x" * 400, count=10)
+ return StreamingResponse(streaming, status_code=200)
+
+ app = Starlette(
+ routes=[Route("/", endpoint=homepage)],
+ middleware=[Middleware(ZstdMiddleware)],
+ )
+
+ client = test_client_factory(app)
+ response = client.get("/", headers={"accept-encoding": "zstd"})
+ assert response.status_code == 200
+ assert response.text == "x" * 4000
+ assert response.headers["Content-Encoding"] == "zstd"
+ assert response.headers["Vary"] == "Accept-Encoding"
+ assert "Content-Length" not in response.headers
+
+
+def test_zstd_streaming_response_identity(test_client_factory: TestClientFactory) -> None:
+ def homepage(request: Request) -> StreamingResponse:
+ async def generator(bytes: bytes, count: int) -> ContentStream:
+ for index in range(count):
+ yield bytes
+
+ streaming = generator(bytes=b"x" * 400, count=10)
+ return StreamingResponse(streaming, status_code=200)
+
+ app = Starlette(
+ routes=[Route("/", endpoint=homepage)],
+ middleware=[Middleware(ZstdMiddleware)],
+ )
+
+ client = test_client_factory(app)
+ response = client.get("/", headers={"accept-encoding": "identity"})
+ assert response.status_code == 200
+ assert response.text == "x" * 4000
+ assert "Content-Encoding" not in response.headers
+ assert response.headers["Vary"] == "Accept-Encoding"
+ assert "Content-Length" not in response.headers
+
+
+def test_zstd_ignored_for_responses_with_encoding_set(
+ test_client_factory: TestClientFactory,
+) -> None:
+ def homepage(request: Request) -> StreamingResponse:
+ async def generator(bytes: bytes, count: int) -> ContentStream:
+ for index in range(count):
+ yield bytes
+
+ streaming = generator(bytes=b"x" * 400, count=10)
+ return StreamingResponse(streaming, status_code=200, headers={"Content-Encoding": "text"})
+
+ app = Starlette(
+ routes=[Route("/", endpoint=homepage)],
+ middleware=[Middleware(ZstdMiddleware)],
+ )
+
+ client = test_client_factory(app)
+ response = client.get("/", headers={"accept-encoding": "zstd, text"})
+ assert response.status_code == 200
+ assert response.text == "x" * 4000
+ assert response.headers["Content-Encoding"] == "text"
+ assert "Vary" not in response.headers
+ assert "Content-Length" not in response.headers
+
+
+def test_zstd_ignored_on_server_sent_events(test_client_factory: TestClientFactory) -> None:
+ def homepage(request: Request) -> StreamingResponse:
+ async def generator(bytes: bytes, count: int) -> ContentStream:
+ for _ in range(count):
+ yield bytes
+
+ streaming = generator(bytes=b"x" * 400, count=10)
+ return StreamingResponse(streaming, status_code=200, media_type="text/event-stream")
+
+ app = Starlette(
+ routes=[Route("/", endpoint=homepage)],
+ middleware=[Middleware(ZstdMiddleware)],
+ )
+
+ client = test_client_factory(app)
+ response = client.get("/", headers={"accept-encoding": "zstd"})
+ assert response.status_code == 200
+ assert response.text == "x" * 4000
+ assert "Content-Encoding" not in response.headers
+ assert "Content-Length" not in response.headers
+
+
+@pytest.mark.anyio
+async def test_zstd_ignored_for_pathsend_responses(tmpdir: Path) -> None:
+ path = tmpdir / "example.txt"
+ with path.open("w") as file:
+ file.write("<file content>")
+
+ events: list[Message] = []
+
+ async def endpoint_with_pathsend(request: Request) -> FileResponse:
+ _ = await request.body()
+ return FileResponse(path)
+
+ app = Starlette(
+ routes=[Route("/", endpoint=endpoint_with_pathsend)],
+ middleware=[Middleware(ZstdMiddleware)],
+ )
+
+ scope = {
+ "type": "http",
+ "version": "3",
+ "method": "GET",
+ "path": "/",
+ "headers": [(b"accept-encoding", b"zstd, text")],
+ "extensions": {"http.response.pathsend": {}},
+ }
+
+ async def receive() -> Message:
+ return {"type": "http.request", "body": b"", "more_body": False}
+
+ async def send(message: Message) -> None:
+ events.append(message)
+
+ await app(scope, receive, send)
+
+ assert len(events) == 2
+ assert events[0]["type"] == "http.response.start"
+ assert events[1]["type"] == "http.response.pathsend"
{ url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181, upload-time = "2024-05-28T17:01:53.112Z" },
]
+[[package]]
+name = "backports-zstd"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/04/12/8080a1b7bce609eb250813519f550b36ad5950b64f0af2738c0fb53e7fb3/backports_zstd-1.0.0.tar.gz", hash = "sha256:8e99702fd4092c26624b914bcd140d03911a16445ba6a74435b29a190469cce3", size = 995991, upload-time = "2025-10-10T07:06:18.481Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5e/79/10389134d3a7e3099798ca55fc82abe9d7f49239c69c8d9c4979b091338c/backports_zstd-1.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:34cd28f44f6b8f70ea5d86c2b3ba26d0d51f94606bd1f0c80bde1f820e8c82b2", size = 435682, upload-time = "2025-10-10T07:03:59.169Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/6e/40d033accd0d54ee0b696f8f2ae0840bd4fae7255b3463ff46b210520e4f/backports_zstd-1.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7ccfd860da6b4c0c1f0f68dc917483977383e1207bdee262d40369fe616fc8", size = 362079, upload-time = "2025-10-10T07:04:00.784Z" },
+ { url = "https://files.pythonhosted.org/packages/73/47/a1ed28ffd9b956aadbde6ad9a8d4adeab38b5cbfdd1d3f3d485a1bb18eba/backports_zstd-1.0.0-cp310-cp310-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:65de196c84b0d2c44fb76a729041de3a292f0128ded1b5ff7c1c4eab948aae0b", size = 505978, upload-time = "2025-10-10T07:04:02.903Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/14/6ea8a2567881ce0a46b7c8376c336f366e6e5dfe84766c45fed7473f0649/backports_zstd-1.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1096d4504557d2deb9e71e1aef9914c651b7aa05c35276d77854fee7a4bdd09a", size = 475592, upload-time = "2025-10-10T07:04:04.275Z" },
+ { url = "https://files.pythonhosted.org/packages/62/27/5782d0bb36adbeec58687a2abf7e1a1659af30782129355456551486794f/backports_zstd-1.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1a0db63d2a112c217a347789aecd38bdd17bc1030fa9d3d256d5d011231852f2", size = 581221, upload-time = "2025-10-10T07:04:05.759Z" },
+ { url = "https://files.pythonhosted.org/packages/69/0b/accbbdbd24940b7a93d8064224b4eb304bd51d68a5e03fd2af3e2b5af268/backports_zstd-1.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0dfab6714325c29d621593b1e9198e47064bb755e601c3e79fde5211a16527f7", size = 640865, upload-time = "2025-10-10T07:04:07.236Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/c4/7c5c5e47565e959a5dd6d2eae4e34e2ca46b6ba123ee1dd548c0c0d316f2/backports_zstd-1.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63076e558ba75b2c016257bdbe6b83b5b9a41fe5b6601b567f1e07890370f2f1", size = 491083, upload-time = "2025-10-10T07:04:09.04Z" },
+ { url = "https://files.pythonhosted.org/packages/47/46/4ef914cfaf8a91fecd01e3d342fd506f450a06109c749a034e3a48ce97b2/backports_zstd-1.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cd445dcb1ec8a8aa38d3c4e9cda7991cacead193bb07cf002f60cfc002d8628", size = 481539, upload-time = "2025-10-10T07:04:10.532Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/f0/ae1dd6cf45d48b535fb6e5a77a107d6cc39db2ae8a9c060762d8fb6bcad2/backports_zstd-1.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d01aa1b91007edd00abc78b3cb7e10ad9394b54a75cbd76b1584524a3b238cfc", size = 509486, upload-time = "2025-10-10T07:04:11.763Z" },
+ { url = "https://files.pythonhosted.org/packages/91/35/a4829b1715e965baa00ef52529f513c8c30de83d3d2f662cbd016ad8861a/backports_zstd-1.0.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d6bbb553640f7ed630223dae9ec93d6f56785d03db0c8385e0c4cfc88d54bdf4", size = 585584, upload-time = "2025-10-10T07:04:13.264Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/b7/3d139188c2803b7e2944cc22ad7e2a974cc9773534c4dd736a136b671160/backports_zstd-1.0.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8d25adbe96f4a3fb6492d8d504e78c1641b06002ca2b578a0b24862ee9fd5a58", size = 631442, upload-time = "2025-10-10T07:04:14.655Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/72/442ada2be3fa510b0a93ca3f353c546c7626690029c3533dd348ea3c7730/backports_zstd-1.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dde864a9c6aaa94eafe4962f59916de3165e99b3fd4d2f6584cd116707aed8ff", size = 495142, upload-time = "2025-10-10T07:04:16.144Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/80/e26f98015801a790262f9637feaebf2028edebd915e196cc1507f4ee7b6f/backports_zstd-1.0.0-cp310-cp310-win32.whl", hash = "sha256:474847d1ac3ed2e4bfca2207bbfd5632110143ddd4fc6ea41ff5c5b05d2fda1d", size = 288590, upload-time = "2025-10-10T07:04:17.755Z" },
+ { url = "https://files.pythonhosted.org/packages/db/39/f322cf4d8b3194353a5bc01db6f2829835d1df273e93ebd1607f130213b5/backports_zstd-1.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5d2fb3f4d53b2f92a26e7fc34b313ac5eebd7ff437f37f8f5c308d72c844fbd7", size = 313505, upload-time = "2025-10-10T07:04:18.895Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/c0/e6ce5b66c48dfe29ec149eee01901be136071dd1692d6f99e14dbd7ba7d1/backports_zstd-1.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:525a1ecb62edd97c6695812fef0e4dc7c2faa5edf3057aa3d8ec9d2dbd0f7799", size = 288707, upload-time = "2025-10-10T07:04:19.968Z" },
+ { url = "https://files.pythonhosted.org/packages/01/0a/cbf3f9cb7ca865eca93744d1b859ed50d28be3f64d83cfd96ad114ed88d6/backports_zstd-1.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:782923d65aa6d0c8c465c32563df70dbdd3e255532de2a2d26e13598fc5f85ae", size = 435683, upload-time = "2025-10-10T07:04:21.097Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/70/65f975ac0e1780963c5bcfae40e822724d7e4bfe902eeef3637a14fb56b1/backports_zstd-1.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6825598589ef9b8c0c4e574170d29d84400be24c2f172b81403435b33c8d103a", size = 362075, upload-time = "2025-10-10T07:04:22.382Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/22/007acd1b0af3a78188c2b71fd4a3284f005826bd93e234e73412944d7b99/backports_zstd-1.0.0-cp311-cp311-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:15863463b7f28049d4511f9f123c3b96d66c3de543315c21ef3bc6b001b20d01", size = 505978, upload-time = "2025-10-10T07:04:23.504Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/d6/f0a148d3f0d0558ace2fc0e7d4f0cc648e88c212665cbf8df718037adde9/backports_zstd-1.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b39da619431f4782f3d8bb0d99a6067db571eab50579527ba168bcc12887d328", size = 475589, upload-time = "2025-10-10T07:04:24.791Z" },
+ { url = "https://files.pythonhosted.org/packages/49/b5/32fcb6342cfa9ca5692b0344961aafd082887e4fad89248f890927522bad/backports_zstd-1.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:411da73bb3eadef58da781c55c6399fc6dba9b898ca05009410138fb1d7fef8d", size = 581218, upload-time = "2025-10-10T07:04:26.493Z" },
+ { url = "https://files.pythonhosted.org/packages/21/00/757aa4952b8f3d955bb62b72360940639c781fc4f39249f5ea40e0b8125b/backports_zstd-1.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1f8b0bc92f5be153a4878188ab0aeab5b9bbff3dc3e9d3ad3b19e29fe4932741", size = 640908, upload-time = "2025-10-10T07:04:27.837Z" },
+ { url = "https://files.pythonhosted.org/packages/37/5f/075c31cbe58fffd8144bc482fea73d2833562159684430b3f1d402fa9f8d/backports_zstd-1.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34cd5bdb76448f2259ea371d6cd62a7e339021e1429fe3c386acb3e58c1f6c61", size = 491121, upload-time = "2025-10-10T07:04:29.045Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/a0/4c4b9a85ff52fe90a3265aa9b5cb7b35bf1a2d48bd1ed4604d7fe1aabfc7/backports_zstd-1.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d251a49e80e1868e132e6edadfbef8dba7ded7751e59a41684cd6da38bbd3507", size = 481544, upload-time = "2025-10-10T07:04:30.174Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/0e/1bd54a04e9f236f5a8d426c00ce0a6d5af6d68735138e9887d5545311761/backports_zstd-1.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a54ea58ddeaab9a1385c368f84fca474b87b052087b62e56ac1ebd10cabac157", size = 509487, upload-time = "2025-10-10T07:04:31.386Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/eb/03a53be8a982e953acd8864d63ca1622ca309d9fbcf1f7ec5e2550b45057/backports_zstd-1.0.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d6272730803dc5b212615f50af7395f2b05155d9415e367492d6dac807edc949", size = 585574, upload-time = "2025-10-10T07:04:32.585Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/90/17810915587c2686e767a5cd2de014e902c76e0a242daf1c4a97544ba1f5/backports_zstd-1.0.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f6a27510ebb9e1cb877aaa26fc5e0303437bd2023e0a24976da854a3421e60e5", size = 631483, upload-time = "2025-10-10T07:04:34.107Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/22/d65a54a803061e475b66164c7d03d2ed889c32eaf32544c2e0d599c20628/backports_zstd-1.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c55f842917ac4405a9779476b1ec8219247f35d86673769cf2d3c140799d3e4a", size = 495147, upload-time = "2025-10-10T07:04:35.958Z" },
+ { url = "https://files.pythonhosted.org/packages/20/94/bdf4e76e148cfac7c324b74f76fbda83c5a587b8a85871bad09722729283/backports_zstd-1.0.0-cp311-cp311-win32.whl", hash = "sha256:c28cfbd6217ba4837d35cdd8cfd5dcf84ad54bffcb531734002e27dcc84c87ca", size = 288686, upload-time = "2025-10-10T07:04:37.132Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/b1/726a07d04b85a687776b04b53a02b7d2c4b666d51b18c44fa2ddaadfe383/backports_zstd-1.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:f009996762b887d1bf9330ac0ce1e83608db0b881f63644ae30f2b6a290cd36b", size = 313630, upload-time = "2025-10-10T07:04:38.358Z" },
+ { url = "https://files.pythonhosted.org/packages/52/e6/727584a8794fa28164e0795441d8b86f89c75a2368dec0aaaa086f7ac58c/backports_zstd-1.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:62ab49843fc7761383aa7bea8105ca70941797c7145647f71fa4340bfd3b747a", size = 288829, upload-time = "2025-10-10T07:04:39.602Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/22/2a68534673efe608d7b2d0de03595d5d1de629616a2f4e394813376eed21/backports_zstd-1.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f9afba11403cf03849464e0f1214b035970d43546a7cdd9d8ee31dc154889e78", size = 435990, upload-time = "2025-10-10T07:04:41.075Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/44/c3f06c172f128bf1160f6122df2a942440e36b8450cf4ba44c69465c5f55/backports_zstd-1.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86498856adc6e8c6f50cbfb1d4afd4e0997d5837fb225245d3fb26008f3c9412", size = 362142, upload-time = "2025-10-10T07:04:42.344Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/0d/f46bba0f0df4dcd3d47160003b956b19329c25f63fe9e910aa17ca9fa0e5/backports_zstd-1.0.0-cp312-cp312-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:de915a8ecd290c601be7b7436291397b0ac1f7841c97c3a13777bb1065881773", size = 506399, upload-time = "2025-10-10T07:04:43.846Z" },
+ { url = "https://files.pythonhosted.org/packages/92/a1/681e03e50379d72e06c3de796fb8cc5880fca8b70b82562b2eb712abf6d1/backports_zstd-1.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9fffb08c5c1b629c96813108183c8b02d6b07ed6ec81cca8d094089e749db4b5", size = 476222, upload-time = "2025-10-10T07:04:44.975Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/ca/8b0a8b959668668c50af6bfad6fea564d2b6becdcffd998e03dfc04c3954/backports_zstd-1.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:064d4dc840bcfd8c5c9b37dcacd4fb27eac473c75006120015a9f88b73368c9b", size = 581678, upload-time = "2025-10-10T07:04:46.459Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/9a/921ec253ad5a592da20bf8ab1a5be16b242722f193e02d7a3678702aeffc/backports_zstd-1.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0051911391c3f934bb48e8ca08f4319d94b08362a40d96a4b5534c60f00deca2", size = 640408, upload-time = "2025-10-10T07:04:48.178Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/8c/0826259b7076cdaaceda1d52f2859c771dc45efed155084a49f538f0ea2e/backports_zstd-1.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e5f3453f0ea32ccf262e11e711ef1a0a986903b8a3a3078bf93fafdd5cf311c", size = 494195, upload-time = "2025-10-10T07:04:49.326Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/a5/75b1c1e26e305f06a7cde591213d5b3c8591b06882ae635b8ffeb8df6f44/backports_zstd-1.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:33bce0351cd0ad7bd9f363740b894e65255eb93d16d05097ef1d60643ce1cc27", size = 482255, upload-time = "2025-10-10T07:04:50.722Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/24/7061610369a5dbadcddc6f340d5aa8304ae58aee07a6a851b8fa24638036/backports_zstd-1.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:820f3cd08c5c8672015b7e52bf04e3e707727e6576d988eadc1799c0c47b33d9", size = 509829, upload-time = "2025-10-10T07:04:52.014Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/28/afc0158ba3d5d5a03560348f9a79fb8a1e0d0ef98f1d176ab37aa887ed5e/backports_zstd-1.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4e327fe73bfc634e8b04b5e0f715c97680987d633f161fd4702027b34685be43", size = 586059, upload-time = "2025-10-10T07:04:53.255Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/0d/68f1fa86a79faee7f6533bced500ee622dde98c9b3b0ddab58a4fe6410d5/backports_zstd-1.0.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4055318ebb7f6ffad99dabd312706599c9e119c834d6c741a946c0d4b3e5be4e", size = 630869, upload-time = "2025-10-10T07:04:54.397Z" },
+ { url = "https://files.pythonhosted.org/packages/83/e1/a529be674d179caf201e5e406dc70a2c4156e182fa777e43f43f6afa69c6/backports_zstd-1.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:79d3c879720ee4987782da55d728919f9294a8ea6fac76c9af84bc06f3b0f942", size = 498686, upload-time = "2025-10-10T07:04:55.593Z" },
+ { url = "https://files.pythonhosted.org/packages/17/9a/075582e942841520c47535f9ff62b728a88565b737ae21dc99ebcc15ef61/backports_zstd-1.0.0-cp312-cp312-win32.whl", hash = "sha256:930ccc283fdf76d1acca9529acd6ccb6cd26cdaf684d69cc6f359683f90357be", size = 288822, upload-time = "2025-10-10T07:04:56.835Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/14/615cd31c0de23e330e13ba77a6aed9a1d27360ebdf5e68b078c54b8cdbdb/backports_zstd-1.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f1bb3e6d21ebfb22070288b7fb47bbb0baaae604890c4087edf5637debb6bd91", size = 313841, upload-time = "2025-10-10T07:04:58.003Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/b8/87b2467bf82eabb4acd4651f193363ec04973baa35141be441bf9e9e98c0/backports_zstd-1.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:f5fe75e5996b5f4712235f9c63cdb7e5932a9cdf3a41232989f8a3ef1667f784", size = 288950, upload-time = "2025-10-10T07:04:59.279Z" },
+ { url = "https://files.pythonhosted.org/packages/19/36/0182161a23009d5439e125d4af7b13d2df0292663e7f87141d5cf76d3060/backports_zstd-1.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c522469a67fef66998fd9eff2195512ca54d78c6fecdf1c466d2b7752dd810b", size = 435481, upload-time = "2025-10-10T07:05:00.833Z" },
+ { url = "https://files.pythonhosted.org/packages/79/ce/6c235828d54d0027838316d9ce284b52e7bc266154f5e57086a7c7796691/backports_zstd-1.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c28546bcffb88ee38a742e3364338c49672d776ea2c73decc05fbf79f045797e", size = 361757, upload-time = "2025-10-10T07:05:02.422Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/ca/7cbc80512df9b89ae39ab3920afbaad733d4b64390b4439e52ef3673da7b/backports_zstd-1.0.0-cp313-cp313-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:9719c14984ca99f5567a5974210d04c75aa02b0124653ee1b1d9a39bf0764fc6", size = 505673, upload-time = "2025-10-10T07:05:03.596Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/bc/ea32d4698fac21fe6cc08a124ae21daa41be03f788f244791c47e31a4360/backports_zstd-1.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a31220e8544c2194c4a7c3bd9f7fb0eee3c0ce5f8306e55df762428159ff0512", size = 475879, upload-time = "2025-10-10T07:05:04.796Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/42/68344db3586455983bdcdffe51253fa4415908e700d50287249ad6589bc9/backports_zstd-1.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3571e35d6682119daf109678a68fa8a9e29f79487ee7ec2da63a7e97562acb8c", size = 581359, upload-time = "2025-10-10T07:05:05.977Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/d0/3d153d78a52a46ce4c363680da7fbc593eeb314150f005c4bf7c2bd5b51f/backports_zstd-1.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:26ccb82bbeb36fffeb3865abe7df9b9b82d6462a488cd2f3c10e91c41c3103cc", size = 642203, upload-time = "2025-10-10T07:05:07.236Z" },
+ { url = "https://files.pythonhosted.org/packages/11/c3/e31b4e591daec3eab2446db971f275d349aad36041236d5f067ab20fa1a9/backports_zstd-1.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d90cfb475d6d08c596ae77a7009cdda7374ecd79354fd75185cf029bf2204620", size = 490828, upload-time = "2025-10-10T07:05:08.446Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/80/ef7d02d846f710fc95c6d7eb3298ef6504e51f8707f24e1624d139f791d5/backports_zstd-1.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b00c9c22cae8c1f87e2f23f9aeda7fee82ff671672b9f5a161a7ba094d9904b", size = 481638, upload-time = "2025-10-10T07:05:10.18Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/9b/f32500bf26ef588ce4f6284f453532d08789e412a5ecd60c501c77c88f8f/backports_zstd-1.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a87c4491036954ae6d15edaf1e6d5b1941e13a9df14d6a9952899713fcfb0796", size = 509228, upload-time = "2025-10-10T07:05:11.313Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/67/f689055f90a2874578b2b3e7c84311c3007b2fa60c51454e8c432203f1c7/backports_zstd-1.0.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8ea8c5d283211bc21c9782db7a8504a275a5b97e883b0bf67f6903a3af48f3d3", size = 585789, upload-time = "2025-10-10T07:05:12.477Z" },
+ { url = "https://files.pythonhosted.org/packages/86/53/dea52bd76a3ba519a4937e6cab6cbdcdc36b618090eabeac998f69d1bb97/backports_zstd-1.0.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e1d12f64d1bd535c782f30b33d1f60c060105d124f9ade22556fefbf36087776", size = 632571, upload-time = "2025-10-10T07:05:14.18Z" },
+ { url = "https://files.pythonhosted.org/packages/43/c8/ce10a94132957f57860b9440fe726615a6a6e8c5fdfee565d8a1b3a573de/backports_zstd-1.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df08eb2735363a11a9222203c3e9a478d7569511bdd9aa2cc64a39e0403cf09a", size = 495124, upload-time = "2025-10-10T07:05:15.398Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/c0/830ea473e3c6133758a9a421157c8d4d5c65408d565336a59403e6bb0b29/backports_zstd-1.0.0-cp313-cp313-win32.whl", hash = "sha256:0309f924ec026d2174297754aeb97fe5fa665cfe0f8bc70e7bb82808a7adcd08", size = 288467, upload-time = "2025-10-10T07:05:16.563Z" },
+ { url = "https://files.pythonhosted.org/packages/75/5a/318d40e1589908a44532e2c850fedfaedbf4e7c75b6fa3cf4b532fcadc84/backports_zstd-1.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:d68f7f72579070bfef7890ba5316701c001e90b4455bb5c2591558b9d53a7f6e", size = 313680, upload-time = "2025-10-10T07:05:17.71Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/c8/bb0067165e9b1066104a88536eac04cfac388abb5d500b3405cf783c96e8/backports_zstd-1.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:911a099122ce7cebed9e1ec64c1fa54a6ab461d6c7cec8d460d8b3a09bbd439f", size = 288699, upload-time = "2025-10-10T07:05:18.904Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/0e/83badde9b389c198a9a45bccd38a9dc5baa7db92e531d4951b1c0686e29a/backports_zstd-1.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:fad9af0c89048a50e67bfd9e3509d710b268d4ae0e47a2bc945dca273a17286d", size = 436173, upload-time = "2025-10-10T07:05:20.083Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/92/d1f5e9f7e1afbb730020e8c7060d6101cad4aa20eb13b7cb98dda9414726/backports_zstd-1.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:1d0459de16491399e6b6d151213964395ba092ba21b7739756f0507533c8e44f", size = 362456, upload-time = "2025-10-10T07:05:21.367Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/0c/165b04a4bd9b39455e5d051f504acab6c5af3583939336bd2c77a2dc6398/backports_zstd-1.0.0-cp313-cp313t-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:2dcf4c080c0fe8f4ca8f1ff560756ae78e6fada721813c1506f8fd3399996646", size = 507618, upload-time = "2025-10-10T07:05:23.083Z" },
+ { url = "https://files.pythonhosted.org/packages/72/45/868e6b66852b64766feb3a3ce28cc74dd86141120ac6740855f90239fb85/backports_zstd-1.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e26b558e0f2413e9499949dd75985a03be008287598916eaa75a67efc52e4f1b", size = 475518, upload-time = "2025-10-10T07:05:24.297Z" },
+ { url = "https://files.pythonhosted.org/packages/44/ff/71021dae5e024d7e12b5078719582b26eeae984f5718846c135134288330/backports_zstd-1.0.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f0a0c11aee04e0a10e9688ef8d9014af888763507bea85a0d7a7ba5220272996", size = 580942, upload-time = "2025-10-10T07:05:25.497Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/64/553009a1d449033fafba311d2e204b19ebb0dfdba069a639965fb6f0bc57/backports_zstd-1.0.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c8aa92bf9407ed1ba62234e085876b628ecd9d2636c0e1e23f2dacf3be21af2a", size = 639934, upload-time = "2025-10-10T07:05:27.147Z" },
+ { url = "https://files.pythonhosted.org/packages/12/da/490a0b80144fb888ae9328f73d7bfa58fd5ccf8bdb81a6d20561ec5a0ff7/backports_zstd-1.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c78c1eaf3fdea00514afe9636e01f94890f1e4c6e8e1dfede48015364b950705", size = 494822, upload-time = "2025-10-10T07:05:28.325Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/d2/0f7702000bd08ff6aa71114b377141f2d30154597dcd9459a08554122fa5/backports_zstd-1.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4ff181018de5afb1b87edf9a88ec7e62b4b053e75b91ec8ac7819042126ca7cf", size = 482001, upload-time = "2025-10-10T07:05:29.591Z" },
+ { url = "https://files.pythonhosted.org/packages/20/78/2cc5dc095b93841eb251d91cf4b3b4c1e5efc15db40f97f003603acaba3f/backports_zstd-1.0.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eed0753c698a21f0d38464c2a6d4d5e770d2ea2e9c3a308f1712d674598a049f", size = 511380, upload-time = "2025-10-10T07:05:30.874Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/b3/328c4835b661b3a9f2c6f2eb6350a9d4bc673e7e5c7d1149ecb235abe774/backports_zstd-1.0.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:18f5d3ed08afcd08b86b305bf167c0f2b582b906742e4bd3c7389050d5b59817", size = 585514, upload-time = "2025-10-10T07:05:32.523Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/31/3d347703f5d913d35edb58e9fbfbf8155dc63d1e6c0ed93eb5205e09d5f1/backports_zstd-1.0.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:7a8c950abe629e5d8ea606e6600dd1d6cd6bddd7a4566cf34201d31244d10ab3", size = 630541, upload-time = "2025-10-10T07:05:33.799Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/ac/323abb5ba0e5da924dec83073464eb87223677c577e0969c90b279700c1f/backports_zstd-1.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:973e74f4e1f19f7879a6a7900e9a268522eb4297100a573ed69969df63f94674", size = 499450, upload-time = "2025-10-10T07:05:35.4Z" },
+ { url = "https://files.pythonhosted.org/packages/81/cb/1d77d6cf3850e804f4994a8106db2830e58638ed0f2d0f92636adb38a38d/backports_zstd-1.0.0-cp313-cp313t-win32.whl", hash = "sha256:870effb06ffb7623af1c8dac35647a1c4b597d3bb0b3f9895c738bd5ad23666c", size = 289410, upload-time = "2025-10-10T07:05:36.776Z" },
+ { url = "https://files.pythonhosted.org/packages/16/59/5ec914419b6db0516794f6f5214b1990e550971fe0867c60ea55262b5d68/backports_zstd-1.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8bb6470186301e84aaa704c8eb339c97dcdec67445e7e197d44665e933807e4e", size = 314778, upload-time = "2025-10-10T07:05:38.637Z" },
+ { url = "https://files.pythonhosted.org/packages/75/88/198e1726f65229f219bb2a72849c9424ba41f6de989c3a8c9bf58118a4a7/backports_zstd-1.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b2d85810393b3be6e8e77d89a165fc67c2a08290a210dbd77e2fc148dbc4106f", size = 289333, upload-time = "2025-10-10T07:05:39.758Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/80/cad971088dd705adedce95e4ce77801cbad61ac9250b4e77fbbb2881c34f/backports_zstd-1.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1315107754808856ddcf187a19cc139cb4a2a65970bd1bafd71718cfd051d32e", size = 435835, upload-time = "2025-10-10T07:05:41.027Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/9f/8c13830b7d698bd270d9aaeebd685670e8955282a3e5f6967521bcb5b2d3/backports_zstd-1.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96bf0a564af74951adfa6addd1c148ab467ba92172cd23b267dd150b0f47fd9e", size = 362191, upload-time = "2025-10-10T07:05:42.594Z" },
+ { url = "https://files.pythonhosted.org/packages/db/b4/dd0d86d04b1dd4d08468e8d980d3ece48d86909b9635f1efebce309b98d4/backports_zstd-1.0.0-cp39-cp39-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:d7c1c6ebedf7bc70c1adca3f4624e1e04b2a0d7a389b065f0c5d6244f6be3dae", size = 506076, upload-time = "2025-10-10T07:05:43.842Z" },
+ { url = "https://files.pythonhosted.org/packages/86/6e/b484e33d8eb13b9379741e9e88daa48c15c9038e9ee9926ebf1096bfed6f/backports_zstd-1.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ea4ff5e162fb61f8421724021eac0a612af0aff2da9e585c96d27c2da924589", size = 475720, upload-time = "2025-10-10T07:05:45.094Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/e6/c49157bb8240ffd4c0abf93306276be4e80d2ef8c1b8465e06bcecece250/backports_zstd-1.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5a6047fb0bef5bbe519b1e46108847e01a48d002b3dfc69af1423a53d8144dda", size = 581396, upload-time = "2025-10-10T07:05:46.389Z" },
+ { url = "https://files.pythonhosted.org/packages/67/24/a900cfdc4dd74306c6b53604ad51af5f38e2353b0d615a3c869051134b3b/backports_zstd-1.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2d510b422e7b2b6ca142082fa85ac360edf77b73108454335ecfd19071c819ff", size = 641053, upload-time = "2025-10-10T07:05:48.012Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/75/5ce7953c6306fc976abf7cf33f0071a10d58c71c94348844ae625dfdee22/backports_zstd-1.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e6349defa266342802d86343b7fc59ee12048bca5f77a9fcb1c1ab9bb894d09", size = 491186, upload-time = "2025-10-10T07:05:49.424Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/db/375410a26abf2ac972fec554122065d774fa037f9ffeedf4f7b05553b01d/backports_zstd-1.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:20b0a1be02b2ee18c74b68a89eec14be98d11f0415a79eb209dce4bc2d6f4e52", size = 481750, upload-time = "2025-10-10T07:05:50.678Z" },
+ { url = "https://files.pythonhosted.org/packages/21/d1/fa7c2d7b7a1c433e4e79c027c54d17f2ffc489ab7e76496b149d9ae6f667/backports_zstd-1.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3595cbc2f4d8a5dc6bd791ba8d9fee2fdfcdfc07206e944c1b3ec3090fcbc99e", size = 509601, upload-time = "2025-10-10T07:05:51.952Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/35/befe5ee9bec078f7f4c9290cefc56d3336b4ee52d17a60293d9dda4589c0/backports_zstd-1.0.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d3eddb298db7a9a1b122c40bcb418a154b6c8f1b54ef7308644e0e67d42c159e", size = 585743, upload-time = "2025-10-10T07:05:53.609Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/0a/cfbf0ae24348be3c3f597717c639e9cbe29692a99ad650c232b8a97c74c1/backports_zstd-1.0.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ef31a9482727e6b335f673a8b8116be186b83ca72be4a07f60684b8220a213e9", size = 631591, upload-time = "2025-10-10T07:05:54.846Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/2d/7c996648c7a7b84a3e8b045fb494466475c1f599374da3c780198bde96c4/backports_zstd-1.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0a6a6d114058735d042116aa9199b0b436236fddcb5f805fb17310fcadddd441", size = 495294, upload-time = "2025-10-10T07:05:56.417Z" },
+ { url = "https://files.pythonhosted.org/packages/be/c8/5a15a4a52506e2e2598d2667ae67404516ea4336535fdd7b7b1b2fffd623/backports_zstd-1.0.0-cp39-cp39-win32.whl", hash = "sha256:8aea1bdc89becb21d1df1cdcc6182b2aa9540addaa20569169e01b25b8996f41", size = 288646, upload-time = "2025-10-10T07:05:57.993Z" },
+ { url = "https://files.pythonhosted.org/packages/67/4e/42409d11a9d324f68a079493c5806d593f54184962e5fff1dc88a1d5e3ba/backports_zstd-1.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:23a40a40fb56f4b47ece5e9cb7048c2e93d9eeb81ad5fb4e68adcaeb699d6b98", size = 313532, upload-time = "2025-10-10T07:05:59.212Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/f8/932b05fd2f98f85c95674f09ae28ccc1638b8cc17d6f566d21ed499ee456/backports_zstd-1.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:2f07bd1c1b478bd8a0bbe413439c24ee08ceb6ebc957a97de3666e8f2e612463", size = 288756, upload-time = "2025-10-10T07:06:01.216Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/35/680ac0ad73676eb1f3bb71f6dd3bbaa2d28a9e4293d3ede4adcd78905b93/backports_zstd-1.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:efa53658c1e617986ed202e7aa8eb23c69fc8f33d01192cd1565e455ed9aa057", size = 409790, upload-time = "2025-10-10T07:06:02.405Z" },
+ { url = "https://files.pythonhosted.org/packages/62/6c/6410c334890b4a43c893b9dcd3cbc8b10f17ea8dced483d9ba200b17ccab/backports_zstd-1.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4386a17c99ce647877298c916f2afeacb238e56cb7cca2d665822a0ee743b5d5", size = 339308, upload-time = "2025-10-10T07:06:03.667Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/b2/ad3e651985b8a2a4876e5adc61100cef07a8caefb87180391f1f5b8c801c/backports_zstd-1.0.0-pp310-pypy310_pp73-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:cbbb0bda54bda18af99961d7d22d7bc7fedcc7d8ca3a04dcde9189494dbfc87a", size = 420356, upload-time = "2025-10-10T07:06:04.984Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/c4/361bde3f570804674b9033ac41cc26735ceb4e33ccce2645079eff62a26f/backports_zstd-1.0.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c49048ec50f81b196ab0f3c49c025912eba1c6e55259b99f11ee6e8c04226ab", size = 393900, upload-time = "2025-10-10T07:06:06.252Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/90/f7bc5c0d204c2312fbe4e62592c92200f19da8840ce8b4a1df56080b7537/backports_zstd-1.0.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6d1fe816c3c31241b0bdcc96364fae689f3e49a923469ad1ad7a9aeb0bbcd67", size = 413862, upload-time = "2025-10-10T07:06:07.506Z" },
+ { url = "https://files.pythonhosted.org/packages/77/2b/9c1949456566228578d30013e81a593577e63e1cae9e72b058e37ae4c5e2/backports_zstd-1.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:96a57f48d2d64c985393bb4ae15b61097d8fc0d56416e790f7cc09bf9212fb87", size = 299722, upload-time = "2025-10-10T07:06:08.661Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/51/f22627d208ab63e97f5441374110363f4b5e0c2ce0b4f2412e753eb12bf1/backports_zstd-1.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8191c019cefaf074c3f05ebec5ad19ec606b7ac1dc915b66a0820268e6f0e327", size = 409687, upload-time = "2025-10-10T07:06:09.844Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/93/50b2ebb2e8f388bb124c4a39974e29f841ef1452d603045e292e107227b9/backports_zstd-1.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:479270cd6385775dca98accaf304e5f011d94280ad4681d3e925a1b4dfd19aaf", size = 339221, upload-time = "2025-10-10T07:06:11.13Z" },
+ { url = "https://files.pythonhosted.org/packages/25/f5/103645f44a92c4de2860b8d6cf6c5414b63956278764f8b7db359bdeae94/backports_zstd-1.0.0-pp311-pypy311_pp73-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:3beab43bfda8e453648b9cce5edcceb5add6c42c331873b41ab1d24232d9c2b0", size = 420355, upload-time = "2025-10-10T07:06:12.283Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/10/e185f05ec85bc05c82d7efdd75528e695c85181eb291cc4c19b2f26153f1/backports_zstd-1.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67469b247c99537b77f7d402580cbb7298fa15ebe3ce6984d89a5b65d4d5a6c2", size = 393900, upload-time = "2025-10-10T07:06:13.508Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/40/3f717216e21617e919d12d6520d0da5b22002e07f12638629acc9e5dcc2e/backports_zstd-1.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6910a9311e7a2987d353f396568f5e401cf4917e2112bf610e62385ad02d8cf4", size = 413863, upload-time = "2025-10-10T07:06:15.531Z" },
+ { url = "https://files.pythonhosted.org/packages/23/f5/cb12f5dd6ac648e92d8cec8b69fd4064bd549c126fb0d3fe6d3dd237afbe/backports_zstd-1.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:85f08363b7ca504a8bceaa2d4333a1a307d2b2056f77a13036a81d7aa3c87b2a", size = 299719, upload-time = "2025-10-10T07:06:17.032Z" },
+]
+
[[package]]
name = "backrefs"
version = "5.9"
[package.optional-dependencies]
full = [
+ { name = "backports-zstd", marker = "python_full_version < '3.14'" },
{ name = "httpx" },
{ name = "itsdangerous" },
{ name = "jinja2" },
[package.metadata]
requires-dist = [
{ name = "anyio", specifier = ">=3.6.2,<5" },
+ { name = "backports-zstd", marker = "python_full_version < '3.14' and extra == 'full'" },
{ name = "httpx", marker = "extra == 'full'", specifier = ">=0.27.0,<0.29.0" },
{ name = "itsdangerous", marker = "extra == 'full'" },
{ name = "jinja2", marker = "extra == 'full'" },