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 ee835b962 fix(python/adbc_driver_manager): load from
venv/etc/adbc/profiles (#4118)
ee835b962 is described below
commit ee835b9627188a8eed403a8f3a5f59cac7fb0ff5
Author: David Li <[email protected]>
AuthorDate: Thu Mar 19 09:36:31 2026 +0900
fix(python/adbc_driver_manager): load from venv/etc/adbc/profiles (#4118)
---
c/driver_manager/adbc_driver_manager.cc | 5 ++-
c/driver_manager/adbc_driver_manager_api.cc | 23 +++++++---
c/driver_manager/adbc_driver_manager_internal.h | 3 +-
c/driver_manager/adbc_driver_manager_test.cc | 8 ++--
ci/scripts/python_venv_test.sh | 25 ++++++-----
go/adbc/drivermgr/adbc_driver_manager.cc | 5 ++-
go/adbc/drivermgr/adbc_driver_manager_api.cc | 23 +++++++---
go/adbc/drivermgr/adbc_driver_manager_internal.h | 3 +-
.../adbc_driver_manager/_lib.pyx | 9 ++++
.../adbc_driver_manager/dbapi.py | 14 +++---
python/adbc_driver_manager/tests/test_profile.py | 50 ++++++++++++++++++++++
11 files changed, 129 insertions(+), 39 deletions(-)
diff --git a/c/driver_manager/adbc_driver_manager.cc
b/c/driver_manager/adbc_driver_manager.cc
index d55a0d224..be20a9e3e 100644
--- a/c/driver_manager/adbc_driver_manager.cc
+++ b/c/driver_manager/adbc_driver_manager.cc
@@ -535,8 +535,9 @@ AdbcStatusCode InternalInitializeProfile(TempDatabase* args,
}
ProfileGuard guard{};
- CHECK_STATUS(args->profile_provider(
- profile.data(), args->additional_search_path_list.c_str(),
&guard.profile, error));
+ CHECK_STATUS(args->profile_provider(profile.data(),
+
args->additional_profile_search_path_list.c_str(),
+ &guard.profile, error));
const char* driver_name = nullptr;
AdbcDriverInitFunc init_func = nullptr;
diff --git a/c/driver_manager/adbc_driver_manager_api.cc
b/c/driver_manager/adbc_driver_manager_api.cc
index 7f49aa65b..19f8e7b4c 100644
--- a/c/driver_manager/adbc_driver_manager_api.cc
+++ b/c/driver_manager/adbc_driver_manager_api.cc
@@ -543,6 +543,18 @@ AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase*
database, const char*
args->driver = value;
} else if (std::strcmp(key, "entrypoint") == 0) {
args->entrypoint = value;
+ } else if (std::strcmp(key, "additional_manifest_search_path_list") == 0) {
+ if (value) {
+ args->additional_manifest_search_path_list = value;
+ } else {
+ args->additional_manifest_search_path_list.clear();
+ }
+ } else if (std::strcmp(key, "additional_profile_search_path_list") == 0) {
+ if (value) {
+ args->additional_profile_search_path_list = value;
+ } else {
+ args->additional_profile_search_path_list.clear();
+ }
} else {
args->options[key] = value;
}
@@ -619,9 +631,9 @@ AdbcStatusCode
AdbcDriverManagerDatabaseSetAdditionalSearchPathList(
TempDatabase* args = reinterpret_cast<TempDatabase*>(database->private_data);
if (additional_search_path_list) {
- args->additional_search_path_list = additional_search_path_list;
+ args->additional_manifest_search_path_list = additional_search_path_list;
} else {
- args->additional_search_path_list.clear();
+ args->additional_manifest_search_path_list.clear();
}
return ADBC_STATUS_OK;
}
@@ -666,9 +678,10 @@ AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase*
database, struct AdbcError*
} else {
const char* entrypoint =
args->entrypoint.empty() ? nullptr : args->entrypoint.c_str();
- const char* additional_paths = args->additional_search_path_list.empty()
- ? nullptr
- :
args->additional_search_path_list.c_str();
+ const char* additional_paths =
+ args->additional_manifest_search_path_list.empty()
+ ? nullptr
+ : args->additional_manifest_search_path_list.c_str();
status = AdbcFindLoadDriver(args->driver.c_str(), entrypoint,
ADBC_VERSION_1_1_0,
args->load_flags, additional_paths,
diff --git a/c/driver_manager/adbc_driver_manager_internal.h
b/c/driver_manager/adbc_driver_manager_internal.h
index 089e1b405..88b02e64c 100644
--- a/c/driver_manager/adbc_driver_manager_internal.h
+++ b/c/driver_manager/adbc_driver_manager_internal.h
@@ -203,7 +203,8 @@ struct TempDatabase {
std::string entrypoint;
AdbcDriverInitFunc init_func = nullptr;
AdbcLoadFlags load_flags = ADBC_LOAD_FLAG_ALLOW_RELATIVE_PATHS;
- std::string additional_search_path_list;
+ std::string additional_manifest_search_path_list;
+ std::string additional_profile_search_path_list;
AdbcConnectionProfileProvider profile_provider = nullptr;
};
diff --git a/c/driver_manager/adbc_driver_manager_test.cc
b/c/driver_manager/adbc_driver_manager_test.cc
index 91969ad19..5a9c08950 100644
--- a/c/driver_manager/adbc_driver_manager_test.cc
+++ b/c/driver_manager/adbc_driver_manager_test.cc
@@ -1542,9 +1542,11 @@ TEST_F(ConnectionProfiles, SetProfileOption) {
ASSERT_THAT(AdbcDatabaseNew(&database.value, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcDatabaseSetOption(&database.value, "profile", "profile",
&error),
IsOkStatus(&error));
- ASSERT_THAT(AdbcDriverManagerDatabaseSetAdditionalSearchPathList(
- &database.value, temp_dir.string().c_str(), &error),
- IsOkStatus(&error));
+ auto search_path = temp_dir.string();
+ ASSERT_THAT(
+ AdbcDatabaseSetOption(&database.value,
"additional_profile_search_path_list",
+ search_path.c_str(), &error),
+ IsOkStatus(&error));
ASSERT_THAT(AdbcDatabaseInit(&database.value, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcDatabaseRelease(&database.value, &error),
IsOkStatus(&error));
diff --git a/ci/scripts/python_venv_test.sh b/ci/scripts/python_venv_test.sh
index a5c0a8efa..8ff652412 100755
--- a/ci/scripts/python_venv_test.sh
+++ b/ci/scripts/python_venv_test.sh
@@ -74,19 +74,18 @@ EOF
"${scratch}"/.venv/bin/python "${scratch}/test2.py"
echo "PASSED: failed manifest contains the proper path in the exception"
- # TODO(https://github.com/apache/arrow-adbc/issues/4087)
-# cat >"${scratch}/test3.py" <<EOF
-# import adbc_driver_manager.dbapi
-
-# with adbc_driver_manager.dbapi.connect(profile="sqlite/dev") as con:
-# with con.cursor() as cur:
-# cur.execute("SELECT 1")
-# assert cur.fetchall() == [(1,)]
-# EOF
-
-# "${scratch}"/.venv/bin/python "${scratch}/test3.py"
-# test -f /tmp/test.db
-# echo "PASSED: find profile"
+ cat >"${scratch}/test3.py" <<EOF
+import adbc_driver_manager.dbapi
+
+with adbc_driver_manager.dbapi.connect(profile="sqlite/dev") as con:
+ with con.cursor() as cur:
+ cur.execute("SELECT 1")
+ assert cur.fetchall() == [(1,)]
+EOF
+
+ "${scratch}"/.venv/bin/python "${scratch}/test3.py"
+ test -f /tmp/test.db
+ echo "PASSED: find profile"
}
main "$@"
diff --git a/go/adbc/drivermgr/adbc_driver_manager.cc
b/go/adbc/drivermgr/adbc_driver_manager.cc
index d55a0d224..be20a9e3e 100644
--- a/go/adbc/drivermgr/adbc_driver_manager.cc
+++ b/go/adbc/drivermgr/adbc_driver_manager.cc
@@ -535,8 +535,9 @@ AdbcStatusCode InternalInitializeProfile(TempDatabase* args,
}
ProfileGuard guard{};
- CHECK_STATUS(args->profile_provider(
- profile.data(), args->additional_search_path_list.c_str(),
&guard.profile, error));
+ CHECK_STATUS(args->profile_provider(profile.data(),
+
args->additional_profile_search_path_list.c_str(),
+ &guard.profile, error));
const char* driver_name = nullptr;
AdbcDriverInitFunc init_func = nullptr;
diff --git a/go/adbc/drivermgr/adbc_driver_manager_api.cc
b/go/adbc/drivermgr/adbc_driver_manager_api.cc
index 7f49aa65b..19f8e7b4c 100644
--- a/go/adbc/drivermgr/adbc_driver_manager_api.cc
+++ b/go/adbc/drivermgr/adbc_driver_manager_api.cc
@@ -543,6 +543,18 @@ AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase*
database, const char*
args->driver = value;
} else if (std::strcmp(key, "entrypoint") == 0) {
args->entrypoint = value;
+ } else if (std::strcmp(key, "additional_manifest_search_path_list") == 0) {
+ if (value) {
+ args->additional_manifest_search_path_list = value;
+ } else {
+ args->additional_manifest_search_path_list.clear();
+ }
+ } else if (std::strcmp(key, "additional_profile_search_path_list") == 0) {
+ if (value) {
+ args->additional_profile_search_path_list = value;
+ } else {
+ args->additional_profile_search_path_list.clear();
+ }
} else {
args->options[key] = value;
}
@@ -619,9 +631,9 @@ AdbcStatusCode
AdbcDriverManagerDatabaseSetAdditionalSearchPathList(
TempDatabase* args = reinterpret_cast<TempDatabase*>(database->private_data);
if (additional_search_path_list) {
- args->additional_search_path_list = additional_search_path_list;
+ args->additional_manifest_search_path_list = additional_search_path_list;
} else {
- args->additional_search_path_list.clear();
+ args->additional_manifest_search_path_list.clear();
}
return ADBC_STATUS_OK;
}
@@ -666,9 +678,10 @@ AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase*
database, struct AdbcError*
} else {
const char* entrypoint =
args->entrypoint.empty() ? nullptr : args->entrypoint.c_str();
- const char* additional_paths = args->additional_search_path_list.empty()
- ? nullptr
- :
args->additional_search_path_list.c_str();
+ const char* additional_paths =
+ args->additional_manifest_search_path_list.empty()
+ ? nullptr
+ : args->additional_manifest_search_path_list.c_str();
status = AdbcFindLoadDriver(args->driver.c_str(), entrypoint,
ADBC_VERSION_1_1_0,
args->load_flags, additional_paths,
diff --git a/go/adbc/drivermgr/adbc_driver_manager_internal.h
b/go/adbc/drivermgr/adbc_driver_manager_internal.h
index 089e1b405..88b02e64c 100644
--- a/go/adbc/drivermgr/adbc_driver_manager_internal.h
+++ b/go/adbc/drivermgr/adbc_driver_manager_internal.h
@@ -203,7 +203,8 @@ struct TempDatabase {
std::string entrypoint;
AdbcDriverInitFunc init_func = nullptr;
AdbcLoadFlags load_flags = ADBC_LOAD_FLAG_ALLOW_RELATIVE_PATHS;
- std::string additional_search_path_list;
+ std::string additional_manifest_search_path_list;
+ std::string additional_profile_search_path_list;
AdbcConnectionProfileProvider profile_provider = nullptr;
};
diff --git a/python/adbc_driver_manager/adbc_driver_manager/_lib.pyx
b/python/adbc_driver_manager/adbc_driver_manager/_lib.pyx
index 95d2c299b..627b6fb38 100644
--- a/python/adbc_driver_manager/adbc_driver_manager/_lib.pyx
+++ b/python/adbc_driver_manager/adbc_driver_manager/_lib.pyx
@@ -631,6 +631,15 @@ cdef class AdbcDatabase(_AdbcHandle):
&c_error)
check_error(status, &c_error)
+ profile_path = _to_bytes(
+ os.path.join(sys.prefix, "etc/adbc/profiles"),
+ "sys.prefix")
+ c_value = profile_path
+ status = AdbcDatabaseSetOption(
+ &self.database, "additional_profile_search_path_list", c_value,
+ &c_error)
+ check_error(status, &c_error)
+
with nogil:
status = AdbcDatabaseInit(&self.database, &c_error)
check_error(status, &c_error)
diff --git a/python/adbc_driver_manager/adbc_driver_manager/dbapi.py
b/python/adbc_driver_manager/adbc_driver_manager/dbapi.py
index 99cbecb20..775baaa52 100644
--- a/python/adbc_driver_manager/adbc_driver_manager/dbapi.py
+++ b/python/adbc_driver_manager/adbc_driver_manager/dbapi.py
@@ -47,7 +47,7 @@ import time
import typing
import warnings
import weakref
-from typing import Any, Dict, List, Literal, NoReturn, Optional, Tuple, Union
+from typing import Any, Dict, List, Literal, Mapping, NoReturn, Optional,
Tuple, Union
try:
import pyarrow
@@ -188,8 +188,8 @@ def connect(
*,
profile: Optional[str] = None,
entrypoint: Optional[str] = None,
- db_kwargs: Optional[Dict[str, Union[str, pathlib.Path]]] = None,
- conn_kwargs: Optional[Dict[str, str]] = None,
+ db_kwargs: Optional[Mapping[str, Union[str, pathlib.Path]]] = None,
+ conn_kwargs: Optional[Mapping[str, str]] = None,
autocommit=False,
) -> "Connection":
"""
@@ -340,7 +340,7 @@ class Connection(_Closeable):
self,
db: Union[_lib.AdbcDatabase, _SharedDatabase],
conn: _lib.AdbcConnection,
- conn_kwargs: Optional[Dict[str, str]] = None,
+ conn_kwargs: Optional[Mapping[str, str]] = None,
*,
autocommit=False,
backend: Optional[_dbapi_backend.DbapiBackend] = None,
@@ -413,7 +413,7 @@ class Connection(_Closeable):
def cursor(
self,
*,
- adbc_stmt_kwargs: Optional[Dict[str, Any]] = None,
+ adbc_stmt_kwargs: Optional[Mapping[str, Any]] = None,
) -> "Cursor":
"""
Create a new cursor for querying the database.
@@ -446,7 +446,7 @@ class Connection(_Closeable):
operation: Union[bytes, str],
parameters=None,
*,
- adbc_stmt_kwargs: Optional[Dict[str, Any]] = None,
+ adbc_stmt_kwargs: Optional[Mapping[str, Any]] = None,
) -> "Cursor":
"""
Execute a query on a new cursor.
@@ -678,7 +678,7 @@ class Cursor(_Closeable):
def __init__(
self,
conn: Connection,
- adbc_stmt_kwargs: Optional[Dict[str, Any]] = None,
+ adbc_stmt_kwargs: Optional[Mapping[str, Any]] = None,
*,
dbapi_backend: Optional[_dbapi_backend.DbapiBackend] = None,
) -> None:
diff --git a/python/adbc_driver_manager/tests/test_profile.py
b/python/adbc_driver_manager/tests/test_profile.py
index 008e06dc4..174285aae 100644
--- a/python/adbc_driver_manager/tests/test_profile.py
+++ b/python/adbc_driver_manager/tests/test_profile.py
@@ -576,3 +576,53 @@ driver = "adbc_driver_sqlite"
# For virtualenv tests: see Compose job python-venv
+
+
+def test_separate_profile_manifest_paths(tmp_path) -> None:
+ # Test that we can have separate paths for profiles and manifests
+ manifest_path = tmp_path / "manifest"
+ profile_path = tmp_path / "profile"
+ manifest_path.mkdir()
+ profile_path.mkdir()
+
+ manifest = """
+ manifest_version = 1
+ [Driver]
+ shared = "adbc_driver_sqlite"
+ """
+
+ profile = """
+ profile_version = 1
+ driver = "adbc_driver_sqlite"
+ [Options]
+ """
+
+ with (manifest_path / "mani.toml").open("w") as sink:
+ sink.write(manifest)
+ with (manifest_path / "prof.toml").open("w") as sink:
+ sink.write(profile)
+
+ with (profile_path / "manifest.toml").open("w") as sink:
+ sink.write(manifest)
+ with (profile_path / "profile.toml").open("w") as sink:
+ sink.write(profile)
+
+ kwargs = {
+ "additional_manifest_search_path_list": str(manifest_path),
+ "additional_profile_search_path_list": str(profile_path),
+ }
+ with dbapi.connect("mani", db_kwargs=kwargs) as conn:
+ with conn.cursor() as cursor:
+ cursor.execute("SELECT sqlite_version()")
+ assert cursor.fetchone() is not None
+ with dbapi.connect("profile://profile", db_kwargs=kwargs) as conn:
+ with conn.cursor() as cursor:
+ cursor.execute("SELECT sqlite_version()")
+ assert cursor.fetchone() is not None
+
+ with pytest.raises(dbapi.ProgrammingError):
+ with dbapi.connect("manifest", db_kwargs=kwargs):
+ pass
+ with pytest.raises(dbapi.ProgrammingError):
+ with dbapi.connect("profile://prof", db_kwargs=kwargs):
+ pass