diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e71d4d67b..53d0e52c2d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,7 +96,7 @@ jobs: strategy: fail-fast: true matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] uses: ./.github/workflows/test.yml with: coverage: ${{ (matrix.python-version == '3.12' || matrix.python-version == '3.8') }} @@ -123,6 +123,9 @@ jobs: version: "0.5.4" enable-cache: true + - name: Install Build Dependencies + run: sudo apt-get install build-essential libpq-dev python3-dev -y + - name: Install dependencies run: | uv sync @@ -190,6 +193,9 @@ jobs: - name: Check out repository uses: actions/checkout@v4 + - name: Install Build Dependencies + run: sudo apt-get install build-essential libpq-dev python3-dev -y + - name: Set up Python uses: actions/setup-python@v5 with: @@ -260,6 +266,9 @@ jobs: - name: Check out repository uses: actions/checkout@v4 + - name: Install Build Dependencies + run: sudo apt-get install build-essential libpq-dev python3-dev -y + - name: Set up Python uses: actions/setup-python@v5 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d0be5130d2..4dc58cc32d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,6 +38,9 @@ jobs: with: python-version: ${{ inputs.python-version }} + - name: Install Build Dependencies + run: sudo apt-get install build-essential libpq-dev python3-dev -y + - name: Install uv uses: astral-sh/setup-uv@v5 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8dcfdb3442..15d294c3ef 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ default_language_version: - python: "3" + python: "3.12" repos: - repo: https://github.com/compilerla/conventional-pre-commit rev: v3.6.0 diff --git a/litestar/channels/backends/psycopg.py b/litestar/channels/backends/psycopg.py index 599d68fa8e..6769b2539d 100644 --- a/litestar/channels/backends/psycopg.py +++ b/litestar/channels/backends/psycopg.py @@ -40,6 +40,7 @@ async def unsubscribe(self, channels: Iterable[str]) -> None: for channel in channels: await self._listener_conn.execute(SQL("UNLISTEN {channel}").format(channel=Identifier(channel))) await self._listener_conn.commit() + self._subscribed_channels = self._subscribed_channels - set(channels) async def stream_events(self) -> AsyncGenerator[tuple[str, bytes], None]: diff --git a/pyproject.toml b/pyproject.toml index f4523472e5..2c838f78f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries", @@ -46,7 +47,7 @@ dependencies = [ "rich-click", "multipart>=1.2.0", # default litestar plugins - "litestar-htmx>=0.4.0" + "litestar-htmx>=0.4.0" ] description = "Litestar - A production-ready, highly performant, extensible ASGI API Framework" keywords = ["api", "rest", "asgi", "litestar", "starlite"] @@ -83,7 +84,8 @@ brotli = ["brotli"] cli = ["jsbeautifier", "uvicorn[standard]", "uvloop>=0.18.0; sys_platform != 'win32'"] cryptography = ["cryptography"] full = [ - "litestar[annotated-types,attrs,brotli,cli,cryptography,jinja,jwt,mako,minijinja,opentelemetry,piccolo,picologging,prometheus,pydantic,redis,sqlalchemy,standard,structlog,valkey]", + "litestar[annotated-types,attrs,brotli,cli,cryptography,jinja,jwt,mako,minijinja,opentelemetry,piccolo,picologging,prometheus,pydantic,redis,sqlalchemy,standard,structlog,valkey]; python_version < \"3.13\"", + "litestar[annotated-types,attrs,brotli,cli,cryptography,jinja,jwt,mako,minijinja,opentelemetry,piccolo,prometheus,pydantic,redis,sqlalchemy,standard,structlog,valkey]; python_version >= \"3.13\"", ] jinja = ["jinja2>=3.1.2"] jwt = [ @@ -94,9 +96,14 @@ mako = ["mako>=1.2.4"] minijinja = ["minijinja>=1.0.0"] opentelemetry = ["opentelemetry-instrumentation-asgi"] piccolo = ["piccolo"] -picologging = ["picologging"] +picologging = ["picologging; python_version < \"3.13\""] prometheus = ["prometheus-client"] -pydantic = ["pydantic", "email-validator", "pydantic-extra-types"] +pydantic = [ + "pydantic", + "email-validator", + "pydantic-extra-types!=2.9.0; python_version < \"3.9\"", + "pydantic-extra-types; python_version >= \"3.9\"", +] redis = ["redis[hiredis]>=4.4.4"] valkey = ["valkey[libvalkey]>=6.0.2"] sqlalchemy = ["advanced-alchemy>=0.2.2"] @@ -130,7 +137,8 @@ dev = [ "trio", "aiosqlite", "asyncpg>=0.29.0", - "psycopg[pool,binary]>=3.1.10,<3.2", + "psycopg[pool,binary]>=3.1.10,<3.2; python_version < \"3.13\"", + "psycopg[pool,c]; python_version >= \"3.13\"", "psycopg2-binary", "psutil>=5.9.8", "hypercorn>=0.16.0", @@ -167,7 +175,8 @@ linting = [ test = [ "covdefaults", "pytest", - "pytest-asyncio", + "pytest-asyncio<=0.24.0; python_version < \"3.9\"", + "pytest-asyncio>0.24.0; python_version >= \"3.9\"", "pytest-cov", "pytest-lazy-fixtures", "pytest-mock", @@ -285,6 +294,8 @@ module = [ "pytimeparse.*", "importlib_resources", "exceptiongroup", + "picologging", + "picologging.*", ] [[tool.mypy.overrides]] diff --git a/tests/unit/test_channels/test_plugin.py b/tests/unit/test_channels/test_plugin.py index 9e36633211..7ddaaf96ef 100644 --- a/tests/unit/test_channels/test_plugin.py +++ b/tests/unit/test_channels/test_plugin.py @@ -170,7 +170,7 @@ def test_create_ws_route_handlers_arbitrary_channels_allowed(channels_backend: C channels_plugin.publish("something", "foo") assert ws.receive_text(timeout=2) == "something" - time.sleep(0.1) + time.sleep(0.4) with client.websocket_connect("/ws/bar") as ws: channels_plugin.publish("something else", "bar") diff --git a/tests/unit/test_kwargs/test_validations.py b/tests/unit/test_kwargs/test_validations.py index f0d524b0ec..37ca305655 100644 --- a/tests/unit/test_kwargs/test_validations.py +++ b/tests/unit/test_kwargs/test_validations.py @@ -46,19 +46,19 @@ def handler(my_key: str = Parameter(**{param_field: "my_key"})) -> None: # type @pytest.mark.parametrize("reserved_kwarg", sorted(RESERVED_KWARGS)) def test_raises_when_reserved_kwargs_are_misused(reserved_kwarg: str) -> None: decorator = post if reserved_kwarg != "socket" else websocket - - exec(f"async def test_fn({reserved_kwarg}: int) -> None: pass") - handler_with_path_param = decorator("/{" + reserved_kwarg + ":int}")(locals()["test_fn"]) + local = dict(locals(), **globals()) + exec(f"async def test_fn({reserved_kwarg}: int) -> None: pass", local, local) + handler_with_path_param = decorator("/{" + reserved_kwarg + ":int}")(local["test_fn"]) with pytest.raises(ImproperlyConfiguredException): Litestar(route_handlers=[handler_with_path_param]) - exec(f"async def test_fn({reserved_kwarg}: int) -> None: pass") - handler_with_dependency = decorator("/", dependencies={reserved_kwarg: Provide(my_dependency)})(locals()["test_fn"]) + exec(f"async def test_fn({reserved_kwarg}: int) -> None: pass", local, local) + handler_with_dependency = decorator("/", dependencies={reserved_kwarg: Provide(my_dependency)})(local["test_fn"]) with pytest.raises(ImproperlyConfiguredException): Litestar(route_handlers=[handler_with_dependency]) - exec(f"async def test_fn({reserved_kwarg}: int = Parameter(query='my_param')) -> None: pass") - handler_with_aliased_param = decorator("/")(locals()["test_fn"]) + exec(f"async def test_fn({reserved_kwarg}: int = Parameter(query='my_param')) -> None: pass", local, local) + handler_with_aliased_param = decorator("/")(local["test_fn"]) with pytest.raises(ImproperlyConfiguredException): Litestar(route_handlers=[handler_with_aliased_param]) diff --git a/tests/unit/test_middleware/test_middleware_handling.py b/tests/unit/test_middleware/test_middleware_handling.py index 790fd64f1c..e038796502 100644 --- a/tests/unit/test_middleware/test_middleware_handling.py +++ b/tests/unit/test_middleware/test_middleware_handling.py @@ -1,8 +1,11 @@ import logging +import sys from dataclasses import dataclass from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, cast import pytest +from _pytest.capture import CaptureFixture +from _pytest.logging import LogCaptureFixture from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint from litestar import Controller, Request, Response, Router, get, post @@ -13,8 +16,6 @@ if TYPE_CHECKING: from typing import Type - from _pytest.logging import LogCaptureFixture - from litestar.types import ASGIApp, Receive, Scope, Send logger = logging.getLogger(__name__) @@ -91,7 +92,7 @@ def handler() -> None: ... assert middleware_instance.arg == 1 -def test_request_body_logging_middleware(caplog: "LogCaptureFixture") -> None: +def test_request_body_logging_middleware(caplog: LogCaptureFixture, capsys: "CaptureFixture[str]") -> None: @dataclass class JSONRequest: name: str @@ -102,13 +103,22 @@ class JSONRequest: def post_handler(data: JSONRequest) -> JSONRequest: return data - with caplog.at_level(logging.INFO): + if sys.version_info < (3, 13): + with caplog.at_level(logging.INFO): + client = create_test_client( + route_handlers=[post_handler], middleware=[MiddlewareProtocolRequestLoggingMiddleware] + ) + response = client.post("/", json={"name": "moishe zuchmir", "age": 40, "programmer": True}) + assert response.status_code == 201 + assert "test logging" in caplog.text + else: client = create_test_client( route_handlers=[post_handler], middleware=[MiddlewareProtocolRequestLoggingMiddleware] ) response = client.post("/", json={"name": "moishe zuchmir", "age": 40, "programmer": True}) assert response.status_code == 201 - assert "test logging" in caplog.text + log = capsys.readouterr() + assert "test logging" in log.err def test_middleware_call_order() -> None: diff --git a/uv.lock b/uv.lock index 5559a6c35b..db82c8796b 100644 --- a/uv.lock +++ b/uv.lock @@ -1,9 +1,11 @@ version = 1 requires-python = ">=3.8, <4.0" resolution-markers = [ - "python_full_version < '3.13' and sys_platform != 'win32'", + "python_full_version >= '3.9' and python_full_version < '3.13' and sys_platform != 'win32'", + "python_full_version < '3.9' and sys_platform != 'win32'", "python_full_version >= '3.13' and sys_platform != 'win32'", - "python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version >= '3.9' and python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version < '3.9' and sys_platform == 'win32'", "python_full_version >= '3.13' and sys_platform == 'win32'", ] @@ -88,17 +90,42 @@ wheels = [ name = "anyio" version = "4.5.2" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.9' and sys_platform != 'win32'", + "python_full_version < '3.9' and sys_platform == 'win32'", +] dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.9'" }, + { name = "idna", marker = "python_full_version < '3.9'" }, + { name = "sniffio", marker = "python_full_version < '3.9'" }, + { name = "typing-extensions", marker = "python_full_version < '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/f9/9a7ce600ebe7804daf90d4d48b1c0510a4561ddce43a596be46676f82343/anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b", size = 171293 } wheels = [ { url = "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl", hash = "sha256:c011ee36bc1e8ba40e5a81cb9df91925c218fe9b778554e0b56a21e1b5d4716f", size = 89766 }, ] +[[package]] +name = "anyio" +version = "4.8.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.9' and python_full_version < '3.13' and sys_platform != 'win32'", + "python_full_version >= '3.13' and sys_platform != 'win32'", + "python_full_version >= '3.9' and python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version >= '3.13' and sys_platform == 'win32'", +] +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, + { name = "idna", marker = "python_full_version >= '3.9'" }, + { name = "sniffio", marker = "python_full_version >= '3.9'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.9' and python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, +] + [[package]] name = "apeye" version = "1.4.1" @@ -1359,7 +1386,8 @@ name = "httpx" version = "0.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio" }, + { name = "anyio", version = "4.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "anyio", version = "4.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, { name = "certifi" }, { name = "httpcore" }, { name = "idna" }, @@ -1554,7 +1582,7 @@ name = "importlib-resources" version = "6.4.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "zipp", marker = "python_full_version < '3.10'" }, + { name = "zipp", marker = "python_full_version < '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/be/f3e8c6081b684f176b761e6a2fef02a0be939740ed6f54109a2951d806f3/importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", size = 43372 } wheels = [ @@ -1747,14 +1775,16 @@ name = "litestar" version = "2.13.0" source = { editable = "." } dependencies = [ - { name = "anyio" }, + { name = "anyio", version = "4.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "anyio", version = "4.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, { name = "click" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "httpx" }, { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, { name = "importlib-resources", marker = "python_full_version < '3.9'" }, { name = "litestar-htmx" }, - { name = "msgspec" }, + { name = "msgspec", version = "0.18.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "msgspec", version = "0.19.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, { name = "multidict" }, { name = "multipart" }, { name = "polyfactory" }, @@ -1796,7 +1826,7 @@ full = [ { name = "minijinja" }, { name = "opentelemetry-instrumentation-asgi" }, { name = "piccolo" }, - { name = "picologging" }, + { name = "picologging", marker = "python_full_version < '3.13'" }, { name = "prometheus-client" }, { name = "pydantic" }, { name = "pydantic-extra-types" }, @@ -1827,7 +1857,7 @@ piccolo = [ { name = "piccolo" }, ] picologging = [ - { name = "picologging" }, + { name = "picologging", marker = "python_full_version < '3.13'" }, ] prometheus = [ { name = "prometheus-client" }, @@ -1872,7 +1902,9 @@ dev = [ { name = "litestar", extra = ["full"] }, { name = "opentelemetry-sdk" }, { name = "psutil" }, - { name = "psycopg", extra = ["binary", "pool"] }, + { name = "psycopg", extra = ["binary"], marker = "python_full_version < '3.13'" }, + { name = "psycopg", extra = ["c"], marker = "python_full_version >= '3.13'" }, + { name = "psycopg", extra = ["pool"] }, { name = "psycopg2-binary" }, { name = "python-dotenv" }, { name = "starlette" }, @@ -1906,7 +1938,8 @@ linting = [ test = [ { name = "covdefaults" }, { name = "pytest" }, - { name = "pytest-asyncio" }, + { name = "pytest-asyncio", version = "0.24.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "pytest-asyncio", version = "0.25.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, { name = "pytest-cov" }, { name = "pytest-lazy-fixtures" }, { name = "pytest-mock" }, @@ -1936,7 +1969,8 @@ requires-dist = [ { name = "jinja2", marker = "extra == 'standard'" }, { name = "jsbeautifier", marker = "extra == 'cli'" }, { name = "jsbeautifier", marker = "extra == 'standard'" }, - { name = "litestar", extras = ["annotated-types", "attrs", "brotli", "cli", "cryptography", "jinja", "jwt", "mako", "minijinja", "opentelemetry", "piccolo", "picologging", "prometheus", "pydantic", "redis", "sqlalchemy", "standard", "structlog", "valkey"], marker = "extra == 'full'" }, + { name = "litestar", extras = ["annotated-types", "attrs", "brotli", "cli", "cryptography", "jinja", "jwt", "mako", "minijinja", "opentelemetry", "piccolo", "picologging", "prometheus", "pydantic", "redis", "sqlalchemy", "standard", "structlog", "valkey"], marker = "python_full_version < '3.13' and extra == 'full'" }, + { name = "litestar", extras = ["annotated-types", "attrs", "brotli", "cli", "cryptography", "jinja", "jwt", "mako", "minijinja", "opentelemetry", "piccolo", "prometheus", "pydantic", "redis", "sqlalchemy", "standard", "structlog", "valkey"], marker = "python_full_version >= '3.13' and extra == 'full'" }, { name = "litestar-htmx", specifier = ">=0.4.0" }, { name = "mako", marker = "extra == 'mako'", specifier = ">=1.2.4" }, { name = "minijinja", marker = "extra == 'minijinja'", specifier = ">=1.0.0" }, @@ -1945,11 +1979,12 @@ requires-dist = [ { name = "multipart", specifier = ">=1.2.0" }, { name = "opentelemetry-instrumentation-asgi", marker = "extra == 'opentelemetry'" }, { name = "piccolo", marker = "extra == 'piccolo'" }, - { name = "picologging", marker = "extra == 'picologging'" }, + { name = "picologging", marker = "python_full_version < '3.13' and extra == 'picologging'" }, { name = "polyfactory", specifier = ">=2.6.3" }, { name = "prometheus-client", marker = "extra == 'prometheus'" }, { name = "pydantic", marker = "extra == 'pydantic'" }, - { name = "pydantic-extra-types", marker = "extra == 'pydantic'" }, + { name = "pydantic-extra-types", marker = "python_full_version >= '3.9' and extra == 'pydantic'" }, + { name = "pydantic-extra-types", marker = "python_full_version < '3.9' and extra == 'pydantic'", specifier = "!=2.9.0" }, { name = "pyjwt", marker = "extra == 'jwt'", specifier = ">=2.9.0" }, { name = "pyyaml" }, { name = "redis", extras = ["hiredis"], marker = "extra == 'redis'", specifier = ">=4.4.4" }, @@ -1979,7 +2014,8 @@ dev = [ { name = "litestar", extras = ["full"] }, { name = "opentelemetry-sdk" }, { name = "psutil", specifier = ">=5.9.8" }, - { name = "psycopg", extras = ["pool", "binary"], specifier = ">=3.1.10,<3.2" }, + { name = "psycopg", extras = ["pool", "binary"], marker = "python_full_version < '3.13'", specifier = ">=3.1.10,<3.2" }, + { name = "psycopg", extras = ["pool", "c"], marker = "python_full_version >= '3.13'" }, { name = "psycopg2-binary" }, { name = "python-dotenv" }, { name = "starlette" }, @@ -2013,7 +2049,8 @@ linting = [ test = [ { name = "covdefaults" }, { name = "pytest" }, - { name = "pytest-asyncio" }, + { name = "pytest-asyncio", marker = "python_full_version < '3.9'", specifier = "<=0.24.0" }, + { name = "pytest-asyncio", marker = "python_full_version >= '3.9'", specifier = ">0.24.0" }, { name = "pytest-cov" }, { name = "pytest-lazy-fixtures" }, { name = "pytest-mock" }, @@ -2255,6 +2292,10 @@ wheels = [ name = "msgspec" version = "0.18.6" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.9' and sys_platform != 'win32'", + "python_full_version < '3.9' and sys_platform == 'win32'", +] sdist = { url = "https://files.pythonhosted.org/packages/5e/fb/42b1865063fddb14dbcbb6e74e0a366ecf1ba371c4948664dde0b0e10f95/msgspec-0.18.6.tar.gz", hash = "sha256:a59fc3b4fcdb972d09138cb516dbde600c99d07c38fd9372a6ef500d2d031b4e", size = 216757 } wheels = [ { url = "https://files.pythonhosted.org/packages/49/54/34c2b70e0d42d876c04f6436c80777d786f25c7536830db5e4ec1aef8788/msgspec-0.18.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:77f30b0234eceeff0f651119b9821ce80949b4d667ad38f3bfed0d0ebf9d6d8f", size = 202537 }, @@ -2294,6 +2335,55 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cd/b2/283d010db6836db2fe059f7ee3c13823927229975ffbe1edcbeded85a556/msgspec-0.18.6-cp39-cp39-win_amd64.whl", hash = "sha256:b5c390b0b0b7da879520d4ae26044d74aeee5144f83087eb7842ba59c02bc090", size = 185801 }, ] +[[package]] +name = "msgspec" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.9' and python_full_version < '3.13' and sys_platform != 'win32'", + "python_full_version >= '3.13' and sys_platform != 'win32'", + "python_full_version >= '3.9' and python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version >= '3.13' and sys_platform == 'win32'", +] +sdist = { url = "https://files.pythonhosted.org/packages/cf/9b/95d8ce458462b8b71b8a70fa94563b2498b89933689f3a7b8911edfae3d7/msgspec-0.19.0.tar.gz", hash = "sha256:604037e7cd475345848116e89c553aa9a233259733ab51986ac924ab1b976f8e", size = 216934 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/40/817282b42f58399762267b30deb8ac011d8db373f8da0c212c85fbe62b8f/msgspec-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d8dd848ee7ca7c8153462557655570156c2be94e79acec3561cf379581343259", size = 190019 }, + { url = "https://files.pythonhosted.org/packages/92/99/bd7ed738c00f223a8119928661167a89124140792af18af513e6519b0d54/msgspec-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0553bbc77662e5708fe66aa75e7bd3e4b0f209709c48b299afd791d711a93c36", size = 183680 }, + { url = "https://files.pythonhosted.org/packages/e5/27/322badde18eb234e36d4a14122b89edd4e2973cdbc3da61ca7edf40a1ccd/msgspec-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe2c4bf29bf4e89790b3117470dea2c20b59932772483082c468b990d45fb947", size = 209334 }, + { url = "https://files.pythonhosted.org/packages/c6/65/080509c5774a1592b2779d902a70b5fe008532759927e011f068145a16cb/msgspec-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e87ecfa9795ee5214861eab8326b0e75475c2e68a384002aa135ea2a27d909", size = 211551 }, + { url = "https://files.pythonhosted.org/packages/6f/2e/1c23c6b4ca6f4285c30a39def1054e2bee281389e4b681b5e3711bd5a8c9/msgspec-0.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3c4ec642689da44618f68c90855a10edbc6ac3ff7c1d94395446c65a776e712a", size = 215099 }, + { url = "https://files.pythonhosted.org/packages/83/fe/95f9654518879f3359d1e76bc41189113aa9102452170ab7c9a9a4ee52f6/msgspec-0.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2719647625320b60e2d8af06b35f5b12d4f4d281db30a15a1df22adb2295f633", size = 218211 }, + { url = "https://files.pythonhosted.org/packages/79/f6/71ca7e87a1fb34dfe5efea8156c9ef59dd55613aeda2ca562f122cd22012/msgspec-0.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:695b832d0091edd86eeb535cd39e45f3919f48d997685f7ac31acb15e0a2ed90", size = 186174 }, + { url = "https://files.pythonhosted.org/packages/24/d4/2ec2567ac30dab072cce3e91fb17803c52f0a37aab6b0c24375d2b20a581/msgspec-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa77046904db764b0462036bc63ef71f02b75b8f72e9c9dd4c447d6da1ed8f8e", size = 187939 }, + { url = "https://files.pythonhosted.org/packages/2b/c0/18226e4328897f4f19875cb62bb9259fe47e901eade9d9376ab5f251a929/msgspec-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:047cfa8675eb3bad68722cfe95c60e7afabf84d1bd8938979dd2b92e9e4a9551", size = 182202 }, + { url = "https://files.pythonhosted.org/packages/81/25/3a4b24d468203d8af90d1d351b77ea3cffb96b29492855cf83078f16bfe4/msgspec-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e78f46ff39a427e10b4a61614a2777ad69559cc8d603a7c05681f5a595ea98f7", size = 209029 }, + { url = "https://files.pythonhosted.org/packages/85/2e/db7e189b57901955239f7689b5dcd6ae9458637a9c66747326726c650523/msgspec-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c7adf191e4bd3be0e9231c3b6dc20cf1199ada2af523885efc2ed218eafd011", size = 210682 }, + { url = "https://files.pythonhosted.org/packages/03/97/7c8895c9074a97052d7e4a1cc1230b7b6e2ca2486714eb12c3f08bb9d284/msgspec-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f04cad4385e20be7c7176bb8ae3dca54a08e9756cfc97bcdb4f18560c3042063", size = 214003 }, + { url = "https://files.pythonhosted.org/packages/61/61/e892997bcaa289559b4d5869f066a8021b79f4bf8e955f831b095f47a4cd/msgspec-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45c8fb410670b3b7eb884d44a75589377c341ec1392b778311acdbfa55187716", size = 216833 }, + { url = "https://files.pythonhosted.org/packages/ce/3d/71b2dffd3a1c743ffe13296ff701ee503feaebc3f04d0e75613b6563c374/msgspec-0.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:70eaef4934b87193a27d802534dc466778ad8d536e296ae2f9334e182ac27b6c", size = 186184 }, + { url = "https://files.pythonhosted.org/packages/b2/5f/a70c24f075e3e7af2fae5414c7048b0e11389685b7f717bb55ba282a34a7/msgspec-0.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f98bd8962ad549c27d63845b50af3f53ec468b6318400c9f1adfe8b092d7b62f", size = 190485 }, + { url = "https://files.pythonhosted.org/packages/89/b0/1b9763938cfae12acf14b682fcf05c92855974d921a5a985ecc197d1c672/msgspec-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:43bbb237feab761b815ed9df43b266114203f53596f9b6e6f00ebd79d178cdf2", size = 183910 }, + { url = "https://files.pythonhosted.org/packages/87/81/0c8c93f0b92c97e326b279795f9c5b956c5a97af28ca0fbb9fd86c83737a/msgspec-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cfc033c02c3e0aec52b71710d7f84cb3ca5eb407ab2ad23d75631153fdb1f12", size = 210633 }, + { url = "https://files.pythonhosted.org/packages/d0/ef/c5422ce8af73928d194a6606f8ae36e93a52fd5e8df5abd366903a5ca8da/msgspec-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d911c442571605e17658ca2b416fd8579c5050ac9adc5e00c2cb3126c97f73bc", size = 213594 }, + { url = "https://files.pythonhosted.org/packages/19/2b/4137bc2ed45660444842d042be2cf5b18aa06efd2cda107cff18253b9653/msgspec-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:757b501fa57e24896cf40a831442b19a864f56d253679f34f260dcb002524a6c", size = 214053 }, + { url = "https://files.pythonhosted.org/packages/9d/e6/8ad51bdc806aac1dc501e8fe43f759f9ed7284043d722b53323ea421c360/msgspec-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5f0f65f29b45e2816d8bded36e6b837a4bf5fb60ec4bc3c625fa2c6da4124537", size = 219081 }, + { url = "https://files.pythonhosted.org/packages/b1/ef/27dd35a7049c9a4f4211c6cd6a8c9db0a50647546f003a5867827ec45391/msgspec-0.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:067f0de1c33cfa0b6a8206562efdf6be5985b988b53dd244a8e06f993f27c8c0", size = 187467 }, + { url = "https://files.pythonhosted.org/packages/3c/cb/2842c312bbe618d8fefc8b9cedce37f773cdc8fa453306546dba2c21fd98/msgspec-0.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f12d30dd6266557aaaf0aa0f9580a9a8fbeadfa83699c487713e355ec5f0bd86", size = 190498 }, + { url = "https://files.pythonhosted.org/packages/58/95/c40b01b93465e1a5f3b6c7d91b10fb574818163740cc3acbe722d1e0e7e4/msgspec-0.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82b2c42c1b9ebc89e822e7e13bbe9d17ede0c23c187469fdd9505afd5a481314", size = 183950 }, + { url = "https://files.pythonhosted.org/packages/e8/f0/5b764e066ce9aba4b70d1db8b087ea66098c7c27d59b9dd8a3532774d48f/msgspec-0.19.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19746b50be214a54239aab822964f2ac81e38b0055cca94808359d779338c10e", size = 210647 }, + { url = "https://files.pythonhosted.org/packages/9d/87/bc14f49bc95c4cb0dd0a8c56028a67c014ee7e6818ccdce74a4862af259b/msgspec-0.19.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60ef4bdb0ec8e4ad62e5a1f95230c08efb1f64f32e6e8dd2ced685bcc73858b5", size = 213563 }, + { url = "https://files.pythonhosted.org/packages/53/2f/2b1c2b056894fbaa975f68f81e3014bb447516a8b010f1bed3fb0e016ed7/msgspec-0.19.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac7f7c377c122b649f7545810c6cd1b47586e3aa3059126ce3516ac7ccc6a6a9", size = 213996 }, + { url = "https://files.pythonhosted.org/packages/aa/5a/4cd408d90d1417e8d2ce6a22b98a6853c1b4d7cb7669153e4424d60087f6/msgspec-0.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5bc1472223a643f5ffb5bf46ccdede7f9795078194f14edd69e3aab7020d327", size = 219087 }, + { url = "https://files.pythonhosted.org/packages/23/d8/f15b40611c2d5753d1abb0ca0da0c75348daf1252220e5dda2867bd81062/msgspec-0.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:317050bc0f7739cb30d257ff09152ca309bf5a369854bbf1e57dffc310c1f20f", size = 187432 }, + { url = "https://files.pythonhosted.org/packages/ea/d0/323f867eaec1f2236ba30adf613777b1c97a7e8698e2e881656b21871fa4/msgspec-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15c1e86fff77184c20a2932cd9742bf33fe23125fa3fcf332df9ad2f7d483044", size = 189926 }, + { url = "https://files.pythonhosted.org/packages/a8/37/c3e1b39bdae90a7258d77959f5f5e36ad44b40e2be91cff83eea33c54d43/msgspec-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3b5541b2b3294e5ffabe31a09d604e23a88533ace36ac288fa32a420aa38d229", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/cb/a2/48f2c15c7644668e51f4dce99d5f709bd55314e47acb02e90682f5880f35/msgspec-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f5c043ace7962ef188746e83b99faaa9e3e699ab857ca3f367b309c8e2c6b12", size = 209272 }, + { url = "https://files.pythonhosted.org/packages/25/3c/aa339cf08b990c3f07e67b229a3a8aa31bf129ed974b35e5daa0df7d9d56/msgspec-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca06aa08e39bf57e39a258e1996474f84d0dd8130d486c00bec26d797b8c5446", size = 211396 }, + { url = "https://files.pythonhosted.org/packages/c7/00/c7fb9d524327c558b2803973cc3f988c5100a1708879970a9e377bdf6f4f/msgspec-0.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e695dad6897896e9384cf5e2687d9ae9feaef50e802f93602d35458e20d1fb19", size = 215002 }, + { url = "https://files.pythonhosted.org/packages/3f/bf/d9f9fff026c1248cde84a5ce62b3742e8a63a3c4e811f99f00c8babf7615/msgspec-0.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3be5c02e1fee57b54130316a08fe40cca53af92999a302a6054cd451700ea7db", size = 218132 }, + { url = "https://files.pythonhosted.org/packages/00/03/b92011210f79794958167a3a3ea64a71135d9a2034cfb7597b545a42606d/msgspec-0.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:0684573a821be3c749912acf5848cce78af4298345cb2d7a8b8948a0a5a27cfe", size = 186301 }, +] + [[package]] name = "multidict" version = "6.1.0" @@ -2743,7 +2833,10 @@ wheels = [ [package.optional-dependencies] binary = [ - { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, + { name = "psycopg-binary", marker = "python_full_version < '3.13' and implementation_name != 'pypy'" }, +] +c = [ + { name = "psycopg-c", marker = "python_full_version >= '3.13' and implementation_name != 'pypy'" }, ] pool = [ { name = "psycopg-pool" }, @@ -2809,6 +2902,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/10/01ec61e06f6bb2305ab66f05f0501431ce5edbb61700e1cd5fa73cf05884/psycopg_binary-3.1.20-cp39-cp39-win_amd64.whl", hash = "sha256:47dd369cb4b263d29aed12ee23b37c03e58bfe656843692d109896c258c554b0", size = 2896197 }, ] +[[package]] +name = "psycopg-c" +version = "3.1.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/49/6960b5e5fc82ab4dbde845bbd430d9f9e049847178b3bbe7f1c49c145667/psycopg_c-3.1.20.tar.gz", hash = "sha256:a8dadb012fce8918b0c35d9e5be3d6ba4495067117ee45fa49644e46be3c43c8", size = 562110 } + [[package]] name = "psycopg-pool" version = "3.2.4" @@ -3217,14 +3316,36 @@ wheels = [ [[package]] name = "pytest-asyncio" -version = "0.23.8" +version = "0.24.0" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.9' and sys_platform != 'win32'", + "python_full_version < '3.9' and sys_platform == 'win32'", +] dependencies = [ - { name = "pytest" }, + { name = "pytest", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 }, +] + +[[package]] +name = "pytest-asyncio" +version = "0.25.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.9' and python_full_version < '3.13' and sys_platform != 'win32'", + "python_full_version >= '3.13' and sys_platform != 'win32'", + "python_full_version >= '3.9' and python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version >= '3.13' and sys_platform == 'win32'", +] +dependencies = [ + { name = "pytest", marker = "python_full_version >= '3.9'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/b4/0b378b7bf26a8ae161c3890c0b48a91a04106c5713ce81b4b080ea2f4f18/pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3", size = 46920 } +sdist = { url = "https://files.pythonhosted.org/packages/72/df/adcc0d60f1053d74717d21d58c0048479e9cab51464ce0d2965b086bd0e2/pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f", size = 53950 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", size = 17663 }, + { url = "https://files.pythonhosted.org/packages/61/d8/defa05ae50dcd6019a95527200d3b3980043df5aa445d40cb0ef9f7f98ab/pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075", size = 19400 }, ] [[package]] @@ -3946,7 +4067,8 @@ name = "starlette" version = "0.41.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio" }, + { name = "anyio", version = "4.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "anyio", version = "4.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1a/4c/9b5764bd22eec91c4039ef4c55334e9187085da2d8a2df7bd570869aae18/starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835", size = 2574159 } @@ -4453,7 +4575,8 @@ name = "watchfiles" version = "0.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio" }, + { name = "anyio", version = "4.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "anyio", version = "4.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870 } wheels = [