From: Daniele Varrazzo Date: Thu, 27 Nov 2025 01:44:54 +0000 (+0100) Subject: feat: allow sql.as_string() and as_bytes() to convert values as literals X-Git-Tag: 3.3.0~6^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e5a354e196b4b2e60b1c83093b089872066a0bd2;p=thirdparty%2Fpsycopg.git feat: allow sql.as_string() and as_bytes() to convert values as literals --- diff --git a/psycopg/psycopg/sql.py b/psycopg/psycopg/sql.py index 227c2d6cc..088ebacb7 100644 --- a/psycopg/psycopg/sql.py +++ b/psycopg/psycopg/sql.py @@ -505,7 +505,7 @@ NULL = SQL("NULL") DEFAULT = SQL("DEFAULT") -def as_string(obj: Composable | Template, context: AdaptContext | None = None) -> str: +def as_string(obj: Any, context: AdaptContext | None = None) -> str: if isinstance(obj, Composable): return obj.as_string(context=context) elif isinstance(obj, Template): @@ -513,10 +513,10 @@ def as_string(obj: Composable | Template, context: AdaptContext | None = None) - return as_string(obj, context) else: - raise TypeError(f"{type(obj).__name__} objects not supported by as_string") + return Literal(obj).as_string(context=context) -def as_bytes(obj: Composable | Template, context: AdaptContext | None = None) -> bytes: +def as_bytes(obj: Any, context: AdaptContext | None = None) -> bytes: if isinstance(obj, Composable): return obj.as_bytes(context=context) elif isinstance(obj, Template): @@ -524,4 +524,4 @@ def as_bytes(obj: Composable | Template, context: AdaptContext | None = None) -> return as_bytes(obj, context) else: - raise TypeError(f"{type(obj).__name__} objects not supported by as_bytes") + return Literal(obj).as_bytes(context=context) diff --git a/tests/test_sql.py b/tests/test_sql.py index 3431d7a07..894fc27ac 100644 --- a/tests/test_sql.py +++ b/tests/test_sql.py @@ -655,25 +655,35 @@ def test_as_string_context(conn): assert query == no_e("select 'foo1'") -def test_as_string_error(): - with pytest.raises(TypeError): - sql.as_string("query") # type: ignore[arg-type] +def test_as_string_literal(): + got = sql.as_string("query") + assert got == no_e("'query'") + + got = sql.as_string(dt.date(1970, 1, 1)) + assert got == no_e("'1970-01-01'::date") def test_as_bytes(): query = sql.as_bytes(sql.SQL("select {}").format("foo")) + assert isinstance(query, bytes) assert query == no_e(b"select 'foo'") def test_as_bytes_context(conn): conn.adapters.register_dumper(str, make_dumper("1")) query = sql.as_bytes(sql.SQL("select {}").format("foo"), context=conn) + assert isinstance(query, bytes) assert query == no_e(b"select 'foo1'") -def test_as_bytes_error(): - with pytest.raises(TypeError): - sql.as_bytes("query") # type: ignore[arg-type] +def test_as_bytes_literal(): + got = sql.as_bytes("query") + assert isinstance(got, bytes) + assert got == no_e(b"'query'") + + got = sql.as_bytes(dt.date(1970, 1, 1)) + assert isinstance(got, bytes) + assert got == no_e(b"'1970-01-01'::date") class TestValues: