]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
feat: allow sql.as_string() and as_bytes() to convert values as literals
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 27 Nov 2025 01:44:54 +0000 (02:44 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 27 Nov 2025 02:00:14 +0000 (03:00 +0100)
psycopg/psycopg/sql.py
tests/test_sql.py

index 227c2d6cc8eb4e60afca5686029243f83a7682ce..088ebacb73941452e70de6b3cfaadfbad75e22a2 100644 (file)
@@ -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)
index 3431d7a0774693b81bc77be73133d3ae28ec7d89..894fc27ac3b7d56c5f5108faa7e7a59388b6d93b 100644 (file)
@@ -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: