This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new f1d6412b8 fix(python/adbc_driver_manager): allow more key types in
get_option (#4734)
f1d6412b8 is described below
commit f1d6412b809784a882ad1c971018e4401c91aecd
Author: Fredrik Fornwall <[email protected]>
AuthorDate: Wed Sep 2 07:17:19 2026 +0200
fix(python/adbc_driver_manager): allow more key types in get_option (#4734)
Cython treats a parameter annotated with a built-in type as [requiring
that exact
type](https://docs.cython.org/en/stable/src/userguide/language_basics.html#types).
So a `key: str`typing rejects both bytes and subclasses of `str` ->
currently things like string-valued enums cannot be used with the
`get_option_*` typed getters (while they can be used with `get_option`):
class Options(str, enum.Enum):
BATCH_ROWS = "adbc.sqlite.query.batch_rows"
connection.get_option_int(Options.BATCH_ROWS)
Fix this by using the same `str | bytes` annotation for the typed
getters as for `get_option`. Cython leaves that union as a Python
object, allowing `_to_bytes()` to validate it with isinstance()` and
accept `bytes`, `str`,and `str` subclasses.
Signed-off-by: Fredrik Fornwall <[email protected]>
---
.../adbc_driver_manager/_lib.pyx | 18 +++++------
python/adbc_driver_manager/tests/test_lowlevel.py | 37 ++++++++++++++++++++++
2 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/python/adbc_driver_manager/adbc_driver_manager/_lib.pyx
b/python/adbc_driver_manager/adbc_driver_manager/_lib.pyx
index f84b71b94..cd0417650 100644
--- a/python/adbc_driver_manager/adbc_driver_manager/_lib.pyx
+++ b/python/adbc_driver_manager/adbc_driver_manager/_lib.pyx
@@ -716,7 +716,7 @@ cdef class AdbcDatabase(_AdbcHandle):
c_len -= 1
return buf[:c_len].decode(encoding, errors)
- def get_option_bytes(self, key: str) -> bytes:
+ def get_option_bytes(self, key: str | bytes) -> bytes:
"""Get the value of a binary option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
@@ -747,7 +747,7 @@ cdef class AdbcDatabase(_AdbcHandle):
return bytes(buf[:c_len])
- def get_option_float(self, key: str) -> float:
+ def get_option_float(self, key: str | bytes) -> float:
"""Get the value of a floating-point option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
@@ -760,7 +760,7 @@ cdef class AdbcDatabase(_AdbcHandle):
check_error(status, &c_error)
return c_value
- def get_option_int(self, key: str) -> int:
+ def get_option_int(self, key: str | bytes) -> int:
"""Get the value of an integer option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
@@ -1096,7 +1096,7 @@ cdef class AdbcConnection(_AdbcHandle):
c_len -= 1
return buf[:c_len].decode(encoding, errors)
- def get_option_bytes(self, key: str) -> bytes:
+ def get_option_bytes(self, key: str | bytes) -> bytes:
"""Get the value of a binary option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
@@ -1127,7 +1127,7 @@ cdef class AdbcConnection(_AdbcHandle):
return bytes(buf[:c_len])
- def get_option_float(self, key: str) -> float:
+ def get_option_float(self, key: str | bytes) -> float:
"""Get the value of a floating-point option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
@@ -1140,7 +1140,7 @@ cdef class AdbcConnection(_AdbcHandle):
check_error(status, &c_error)
return c_value
- def get_option_int(self, key: str) -> int:
+ def get_option_int(self, key: str | bytes) -> int:
"""Get the value of an integer option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
@@ -1718,7 +1718,7 @@ cdef class AdbcStatement(_AdbcHandle):
c_len -= 1
return buf[:c_len].decode(encoding, errors)
- def get_option_bytes(self, key: str) -> bytes:
+ def get_option_bytes(self, key: str | bytes) -> bytes:
"""Get the value of a binary option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
@@ -1749,7 +1749,7 @@ cdef class AdbcStatement(_AdbcHandle):
return bytes(buf[:c_len])
- def get_option_float(self, key: str) -> float:
+ def get_option_float(self, key: str | bytes) -> float:
"""Get the value of a floating-point option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
@@ -1762,7 +1762,7 @@ cdef class AdbcStatement(_AdbcHandle):
check_error(status, &c_error)
return c_value
- def get_option_int(self, key: str) -> int:
+ def get_option_int(self, key: str | bytes) -> int:
"""Get the value of an integer option."""
cdef CAdbcError c_error = empty_error()
cdef CAdbcStatusCode status
diff --git a/python/adbc_driver_manager/tests/test_lowlevel.py
b/python/adbc_driver_manager/tests/test_lowlevel.py
index ffd77b292..9017420f7 100644
--- a/python/adbc_driver_manager/tests/test_lowlevel.py
+++ b/python/adbc_driver_manager/tests/test_lowlevel.py
@@ -104,6 +104,43 @@ class ExampleEnum(enum.Enum):
BAR = "BAR"
+class ExampleStringEnum(str, enum.Enum):
+ BATCH_ROWS = "adbc.sqlite.query.batch_rows"
+ BIND_BY_NAME = "adbc.statement.bind_by_name"
+ CONNECTION_AUTOCOMMIT = "adbc.connection.autocommit"
+ DATABASE_URI = "uri"
+
+
[email protected]("key_as_bytes", [False, True], ids=["str-subclass",
"bytes"])
[email protected]
+def test_typed_get_option_key_types(sqlite_raw, key_as_bytes) -> None:
+ def key(option: ExampleStringEnum) -> str | bytes:
+ if key_as_bytes:
+ return option.value.encode()
+ return option
+
+ database, connection = sqlite_raw
+ assert
database.get_option_bytes(key(ExampleStringEnum.DATABASE_URI)).startswith(
+ b"file:"
+ )
+ assert database.get_option_float(key(ExampleStringEnum.BATCH_ROWS)) ==
1024.0
+ assert database.get_option_int(key(ExampleStringEnum.BATCH_ROWS)) == 1024
+
+ assert (
+
connection.get_option_bytes(key(ExampleStringEnum.CONNECTION_AUTOCOMMIT))
+ == b"true"
+ )
+ assert connection.get_option_float(key(ExampleStringEnum.BATCH_ROWS)) ==
1024.0
+ assert connection.get_option_int(key(ExampleStringEnum.BATCH_ROWS)) == 1024
+
+ with adbc_driver_manager.AdbcStatement(connection) as statement:
+ assert (
+ statement.get_option_bytes(key(ExampleStringEnum.BIND_BY_NAME)) ==
b"false"
+ )
+ assert statement.get_option_float(key(ExampleStringEnum.BATCH_ROWS))
== 1024.0
+ assert statement.get_option_int(key(ExampleStringEnum.BATCH_ROWS)) ==
1024
+
+
@pytest.mark.sqlite
def test_database_init(tmp_path) -> None:
option = "adbc.sqlite.query.batch_rows"