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

Reply via email to