Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist -i 3.9 3.10 3.11 3.12 3.13 3.14 pypy3.9 pypy3.10 pypy3.11
args: --release --out dist -i 3.10 3.11 3.12 3.13 3.14 pypy3.10 pypy3.11
sccache: 'true'
manylinux: auto
before-script-linux: |
Expand Down Expand Up @@ -71,7 +71,7 @@ jobs:
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist -i 3.9 3.10 3.11 3.12 3.13 3.14
args: --release --out dist -i 3.10 3.11 3.12 3.13 3.14
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -112,7 +112,7 @@ jobs:
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist -i 3.9 3.10 3.11 3.12 3.13 3.14 pypy3.9 pypy3.10 pypy3.11
args: --release --out dist -i 3.10 3.11 3.12 3.13 3.14 pypy3.10 pypy3.11
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -168,7 +168,7 @@ jobs:
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist -i 3.9 3.10 3.11 3.12 3.13 3.14 pypy3.9 pypy3.10 pypy3.11
args: --release --out dist -i 3.10 3.11 3.12 3.13 3.14 pypy3.10 pypy3.11
manylinux: musllinux_1_2
- name: Upload wheels
uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
name: ${{matrix.job.os}}-${{matrix.py_version}}-${{ matrix.postgres_version }}
strategy:
matrix:
py_version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
py_version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
postgres_version: ["14", "15", "16", "17"]
job:
- os: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions examples/aiohttp/start_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ async def start_db_pool(app: web.Application) -> None:

async def stop_db_pool(app: web.Application) -> None:
"""Close database connection pool."""
db_pool = cast(PSQLPool, app.db_pool)
db_pool = cast("PSQLPool", app.db_pool)
await db_pool.close()


async def pg_pool_example(request: web.Request) -> Any:
db_pool = cast(PSQLPool, request.app["db_pool"])
db_pool = cast("PSQLPool", request.app["db_pool"])
connection = await db_pool.connection()
await asyncio.sleep(10)
query_result = await connection.execute(
Expand Down
2 changes: 1 addition & 1 deletion examples/fastapi/advanced_example.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Start example
import asyncio
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from typing import AsyncGenerator

import uvicorn
from fastapi import FastAPI
Expand Down
6 changes: 3 additions & 3 deletions examples/fastapi/start_example.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Start example
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from typing import AsyncGenerator, cast
from typing import Annotated, cast

import uvicorn
from fastapi import Depends, FastAPI, Request
from fastapi.responses import JSONResponse
from psqlpy import Connection, PSQLPool
from typing_extensions import Annotated


@asynccontextmanager
Expand All @@ -26,7 +26,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:

async def db_connection(request: Request) -> Connection:
"""Retrieve new connection from connection pool and return it."""
return await cast(PSQLPool, request.app.state.db_pool).connection()
return await cast("PSQLPool", request.app.state.db_pool).connection()


@app.get("/")
Expand Down
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "maturin"

[project]
name = "psqlpy"
requires-python = ">=3.8"
requires-python = ">=3.10"
keywords = [
"postgresql",
"psql",
Expand All @@ -27,8 +27,6 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down
9 changes: 5 additions & 4 deletions python/psqlpy/_internal/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import types
import typing
from collections.abc import Awaitable, Callable, Mapping, Sequence
from enum import Enum
from io import BytesIO
from ipaddress import IPv4Address, IPv6Address
from typing import Any, Awaitable, Callable, Mapping, Sequence, TypeVar
from typing import Any, TypeAlias, TypeVar

from typing_extensions import Buffer, Self, TypeAlias
from typing_extensions import Buffer, Self

_CustomClass = TypeVar(
"_CustomClass",
Expand All @@ -22,7 +23,7 @@ class QueryResult:
@typing.overload
def result(
self: Self,
as_tuple: typing.Literal[None] = None,
as_tuple: None = None,
custom_decoders: dict[str, Callable[[bytes], Any]] | None = None,
) -> list[dict[str, Any]]: ...
@typing.overload
Expand Down Expand Up @@ -112,7 +113,7 @@ class SingleQueryResult:
@typing.overload
def result(
self: Self,
as_tuple: typing.Literal[None] = None,
as_tuple: None = None,
custom_decoders: dict[str, Callable[[bytes], Any]] | None = None,
) -> dict[str, Any]: ...
@typing.overload
Expand Down
3 changes: 2 additions & 1 deletion python/psqlpy/_internal/extra_types.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import typing
from datetime import date, datetime, time, timedelta
from decimal import Decimal
from ipaddress import IPv4Address, IPv6Address
from typing import TypeAlias
from uuid import UUID

from typing_extensions import Self, TypeAlias
from typing_extensions import Self

class SmallInt:
"""Represent SmallInt in PostgreSQL and `i16` in Rust."""
Expand Down
2 changes: 1 addition & 1 deletion python/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
import random
from typing import AsyncGenerator
from collections.abc import AsyncGenerator
from urllib import parse

import pytest
Expand Down
2 changes: 1 addition & 1 deletion python/tests/test_kwargs_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,6 @@ async def test_failed_no_parameter(
async with psql_pool.acquire() as conn:
with pytest.raises(expected_exception=PyToRustValueMappingError):
await conn.execute(
querystring=(f"SELECT * FROM {table_name} " "WHERE name = $(name)p"), # noqa: ISC001
querystring=(f"SELECT * FROM {table_name} WHERE name = $(name)p"),
parameters={"mistake": "wow"},
)
9 changes: 5 additions & 4 deletions python/tests/test_row_factories.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, Callable, Dict, Type
from typing import Any

import pytest
from psqlpy import ConnectionPool
Expand Down Expand Up @@ -53,9 +54,9 @@ class ValidationTestModel:
name: str

def to_class(
class_: Type[ValidationTestModel],
) -> Callable[[Dict[str, Any]], ValidationTestModel]:
def to_class_inner(row: Dict[str, Any]) -> ValidationTestModel:
class_: type[ValidationTestModel],
) -> Callable[[dict[str, Any]], ValidationTestModel]:
def to_class_inner(row: dict[str, Any]) -> ValidationTestModel:
return class_(**row)

return to_class_inner
Expand Down
13 changes: 8 additions & 5 deletions python/tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@ async def test_transaction_init_parameters(
deferrable: bool | None,
read_variant: ReadVariant | None,
) -> None:
async with psql_pool.acquire() as connection, connection.transaction(
isolation_level=isolation_level,
deferrable=deferrable,
read_variant=read_variant,
) as transaction:
async with (
psql_pool.acquire() as connection,
connection.transaction(
isolation_level=isolation_level,
deferrable=deferrable,
read_variant=read_variant,
) as transaction,
):
await transaction.execute("SELECT 1")
try:
await transaction.execute(
Expand Down
124 changes: 75 additions & 49 deletions python/tests/test_value_converter.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import datetime
import sys
import uuid
import zoneinfo
from decimal import Decimal
from enum import Enum
from ipaddress import IPv4Address
from typing import Any, Dict, List, Tuple, Union
from typing import Annotated, Any

import pytest
from psqlpy import ConnectionPool
Expand Down Expand Up @@ -54,7 +54,6 @@
VarCharArray,
)
from pydantic import BaseModel
from typing_extensions import Annotated

from tests.conftest import DefaultPydanticModel, DefaultPythonModelClass

Expand Down Expand Up @@ -82,19 +81,17 @@
142574,
tzinfo=datetime.timezone.utc,
)
if sys.version_info >= (3, 9):
import zoneinfo

now_datetime_with_tz_in_asia_jakarta = datetime.datetime(
2024,
4,
13,
17,
3,
46,
142574,
tzinfo=zoneinfo.ZoneInfo(key="Asia/Jakarta"),
)

now_datetime_with_tz_in_asia_jakarta = datetime.datetime(
2024,
4,
13,
17,
3,
46,
142574,
tzinfo=zoneinfo.ZoneInfo(key="Asia/Jakarta"),
)


async def test_as_class(
Expand Down Expand Up @@ -147,6 +144,9 @@ async def test_as_class(
("MONEY", Money(99999999999999999), 99999999999999999),
("MONEY", 99999999999999999, 99999999999999999),
("NUMERIC(5, 2)", Decimal("120.12"), Decimal("120.12")),
("NUMERIC(5, 2)", Decimal("120.123"), Decimal("120.12")),
("NUMERIC(5, 2)", Decimal(120), Decimal(120)),
("NUMERIC(5, 3)", Decimal("12.123"), Decimal("12.123")),
("FLOAT4", Float32(32.12329864501953), 32.12329864501953),
("FLOAT4", 32.12329864501953, 32.12329864501953),
("FLOAT8", Float64(32.12329864501953), 32.12329864501953),
Expand Down Expand Up @@ -520,37 +520,37 @@ class ValidateModelForCustomType(BaseModel):
timestampz_: datetime.datetime
uuid_: uuid.UUID
inet_: IPv4Address
jsonb_: Dict[str, List[Union[str, int, List[str]]]]
json_: Dict[str, List[Union[str, int, List[str]]]]
point_: Tuple[float, float]
box_: Tuple[Tuple[float, float], Tuple[float, float]]
path_: List[Tuple[float, float]]
line_: Annotated[List[float], 3]
lseg_: Annotated[List[Tuple[float, float]], 2]
circle_: Tuple[Tuple[float, float], float]

varchar_arr: List[str]
varchar_arr_mdim: List[List[str]]
text_arr: List[str]
bool_arr: List[bool]
int2_arr: List[int]
int4_arr: List[int]
int8_arr: List[int]
float8_arr: List[float]
date_arr: List[datetime.date]
time_arr: List[datetime.time]
timestamp_arr: List[datetime.datetime]
timestampz_arr: List[datetime.datetime]
uuid_arr: List[uuid.UUID]
inet_arr: List[IPv4Address]
jsonb_arr: List[Dict[str, List[Union[str, int, List[str]]]]]
json_arr: List[Dict[str, List[Union[str, int, List[str]]]]]
point_arr: List[Tuple[float, float]]
box_arr: List[Tuple[Tuple[float, float], Tuple[float, float]]]
path_arr: List[List[Tuple[float, float]]]
line_arr: List[Annotated[List[float], 3]]
lseg_arr: List[Annotated[List[Tuple[float, float]], 2]]
circle_arr: List[Tuple[Tuple[float, float], float]]
jsonb_: dict[str, list[str | int | list[str]]]
json_: dict[str, list[str | int | list[str]]]
point_: tuple[float, float]
box_: tuple[tuple[float, float], tuple[float, float]]
path_: list[tuple[float, float]]
line_: Annotated[list[float], 3]
lseg_: Annotated[list[tuple[float, float]], 2]
circle_: tuple[tuple[float, float], float]

varchar_arr: list[str]
varchar_arr_mdim: list[list[str]]
text_arr: list[str]
bool_arr: list[bool]
int2_arr: list[int]
int4_arr: list[int]
int8_arr: list[int]
float8_arr: list[float]
date_arr: list[datetime.date]
time_arr: list[datetime.time]
timestamp_arr: list[datetime.datetime]
timestampz_arr: list[datetime.datetime]
uuid_arr: list[uuid.UUID]
inet_arr: list[IPv4Address]
jsonb_arr: list[dict[str, list[str | int | list[str]]]]
json_arr: list[dict[str, list[str | int | list[str]]]]
point_arr: list[tuple[float, float]]
box_arr: list[tuple[tuple[float, float], tuple[float, float]]]
path_arr: list[list[tuple[float, float]]]
line_arr: list[Annotated[list[float], 3]]
lseg_arr: list[Annotated[list[tuple[float, float]], 2]]
circle_arr: list[tuple[tuple[float, float], float]]

test_inner_value: ValidateModelForInnerValueType
test_enum_type: TestEnum
Expand Down Expand Up @@ -695,7 +695,7 @@ async def test_row_factory_query_result(
f"SELECT * FROM {table_name}",
)

def row_factory(db_result: Dict[str, Any]) -> List[str]:
def row_factory(db_result: dict[str, Any]) -> list[str]:
return list(db_result.keys())

as_row_factory = select_result.row_factory(
Expand All @@ -715,7 +715,7 @@ async def test_row_factory_single_query_result(
f"SELECT * FROM {table_name} LIMIT 1",
)

def row_factory(db_result: Dict[str, Any]) -> List[str]:
def row_factory(db_result: dict[str, Any]) -> list[str]:
return list(db_result.keys())

as_row_factory = select_result.row_factory(
Expand Down Expand Up @@ -830,11 +830,37 @@ async def test_empty_array(
NumericArray([Decimal("121.23"), Decimal("188.99")]),
[Decimal("121.23"), Decimal("188.99")],
),
(
"NUMERIC(5, 2) ARRAY",
NumericArray([Decimal("121.123"), Decimal("188.99")]),
[
Decimal("121.12").quantize(Decimal("100.00")),
Decimal("188.99").quantize(Decimal("100.00")),
],
),
(
"NUMERIC(5, 2) ARRAY",
NumericArray([Decimal(121), Decimal(188)]),
[Decimal(121), Decimal(188)],
),
(
"NUMERIC(5, 2) ARRAY",
NumericArray([[Decimal("121.23")], [Decimal("188.99")]]),
[[Decimal("121.23")], [Decimal("188.99")]],
),
(
"NUMERIC(5, 2) ARRAY",
NumericArray([[Decimal("121.123")], [Decimal("188.99")]]),
[
[Decimal("121.12").quantize(Decimal("100.00"))],
[Decimal("188.99").quantize(Decimal("100.00"))],
],
),
(
"NUMERIC(5, 2) ARRAY",
NumericArray([[Decimal(121)], [Decimal(188)]]),
[[Decimal(121)], [Decimal(188)]],
),
("FLOAT4 ARRAY", [], []),
(
"FLOAT4 ARRAY",
Expand Down
Loading
Loading