apache / arrow-adbc

Database connectivity API standard and libraries for Apache Arrow
https://arrow.apache.org/adbc/
Apache License 2.0
385 stars 98 forks source link

python/driver/snowflake: TypeError: __init__() got multiple values for keyword argument 'database' #1047

Closed sfc-gh-twhite closed 1 year ago

sfc-gh-twhite commented 1 year ago

I'm using the following libraries to connect to Snowflake with ADBC:

adbc-driver-flightsql==0.6.0 adbc-driver-manager==0.6.0 adbc-driver-snowflake==0.6.0

I'm encountering an error in specifying only the conn_kwargs to establish a connection.

import os
import adbc_driver_snowflake.dbapi
from dotenv import load_dotenv

load_dotenv(override=True)

conn = adbc_driver_snowflake.dbapi.connect(conn_kwargs={
    "_".join(k.split("_")[1:]).lower(): v
    for k, v in os.environ.items()
    if k.upper().startswith("SNOWFLAKE")
})

I've ensured the parameter isn't somehow duplicated.

image

Could this be from?

https://github.com/apache/arrow-adbc/blob/a9c381d2203b28558739f99a8e770d6ab6a50b66/python/adbc_driver_snowflake/adbc_driver_snowflake/dbapi.py#L120

This is normally how I setup my connections with the Snowflake Connector for Python.

image

lidavidm commented 1 year ago

What is the traceback?

sfc-gh-twhite commented 1 year ago

Should have included that, sorry!

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[12], line 7
      3 from dotenv import load_dotenv
      5 load_dotenv(override=True)
----> 7 conn = adbc_driver_snowflake.dbapi.connect(conn_kwargs={
      8     "_".join(k.split("_")[1:]).lower(): v
      9     for k, v in os.environ.items()
     10     if k.upper().startswith("SNOWFLAKE")
     11 })

File [/opt/conda/lib/python3.11/site-packages/adbc_driver_snowflake/dbapi.py:120](https://vscode-remote+dev-002dcontainer-002b7b22686f737450617468223a222f55736572732f7477686974652f5653436f646550726f6a656374732f736e6f77666c616b652d616462632d6578616d706c6573222c22636f6e66696746696c65223a7b22246d6964223a312c22667350617468223a222f55736572732f7477686974652f5653436f646550726f6a656374732f736e6f77666c616b652d616462632d6578616d706c65732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c2265787465726e616c223a2266696c653a2f2f2f55736572732f7477686974652f5653436f646550726f6a656374732f736e6f77666c616b652d616462632d6578616d706c65732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c2270617468223a222f55736572732f7477686974652f5653436f646550726f6a656374732f736e6f77666c616b652d616462632d6578616d706c65732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c22736368656d65223a2266696c65227d7d.vscode-resource.vscode-cdn.net/opt/conda/lib/python3.11/site-packages/adbc_driver_snowflake/dbapi.py:120), in connect(uri, db_kwargs, conn_kwargs, **kwargs)
    118 try:
    119     db = adbc_driver_snowflake.connect(uri, db_kwargs=db_kwargs)
--> 120     conn = adbc_driver_manager.AdbcConnection(db, **(conn_kwargs or {}))
    121     return adbc_driver_manager.dbapi.Connection(db, conn, **kwargs)
    122 except Exception:

File [/opt/conda/lib/python3.11/site-packages/adbc_driver_manager/_lib.pyx:632](https://vscode-remote+dev-002dcontainer-002b7b22686f737450617468223a222f55736572732f7477686974652f5653436f646550726f6a656374732f736e6f77666c616b652d616462632d6578616d706c6573222c22636f6e66696746696c65223a7b22246d6964223a312c22667350617468223a222f55736572732f7477686974652f5653436f646550726f6a656374732f736e6f77666c616b652d616462632d6578616d706c65732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c2265787465726e616c223a2266696c653a2f2f2f55736572732f7477686974652f5653436f646550726f6a656374732f736e6f77666c616b652d616462632d6578616d706c65732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c2270617468223a222f55736572732f7477686974652f5653436f646550726f6a656374732f736e6f77666c616b652d616462632d6578616d706c65732f2e646576636f6e7461696e65722f646576636f6e7461696e65722e6a736f6e222c22736368656d65223a2266696c65227d7d.vscode-resource.vscode-cdn.net/opt/conda/lib/python3.11/site-packages/adbc_driver_manager/_lib.pyx:632), in adbc_driver_manager._lib.AdbcConnection.__init__()

TypeError: __init__() got multiple values for keyword argument 'database'
lidavidm commented 1 year ago

I'm guessing the fact that there's also a named parameter named database is screwing it up. That said, the option name is actually "adbc.snowflake.sql.db", not "database", and it needs to be passed as db_kwargs. (See adbc_driver_snowflake.DatabaseOptions.)

sfc-gh-twhite commented 1 year ago

That would make sense! I still seem to need help to run into trouble. I can get connected using a pure URI, but when I specify the arguments in various ways optionally, it doesn't establish the various contexts.

I rewrote the first part of my code to organize things a bit more for testing purposes:

import os
import adbc_driver_snowflake.dbapi
from dotenv import load_dotenv

load_dotenv(override=True)

connection_params = {
    "_".join(k.split("_")[1:]).lower(): v
    for k, v in os.environ.items()
    if k.upper().startswith("SNOWFLAKE")
}

def format_uri(connection_params) -> str:
    user = connection_params.get('user')
    password = connection_params.get('password')
    account = connection_params.get('account')
    return f"{user}:{password}@{account}"

Now I am trying both (swapping db and database)

conn = adbc_driver_snowflake.dbapi.connect(
    uri=format_uri(connection_params),
    db_kwargs={
        "db": "TWHITE",
        "schema": "COMMON",
        "role": "SYSADMIN"
    },
)

cur = conn.cursor()
cur.execute(operation="SELECT CURRENT_DATABASE();")
cur.fetchall()

and

conn = adbc_driver_snowflake.dbapi.connect(
    uri=format_uri(connection_params),
    db_kwargs={
        "database": "TWHITE",
        "schema": "COMMON",
        "role": "SYSADMIN"
    },
)

cur = conn.cursor()
cur.execute(operation="SELECT CURRENT_DATABASE();")
cur.fetchall()

and it keeps resulting in [(None,)].

I can get by just using the URI, but this will take me a little while to get used to. :)

lidavidm commented 1 year ago

So again: the option isn't schema, it's adbc.snowflake.sql.schema. Does that work for you? The dev docs have an example of some of the other options.

sfc-gh-twhite commented 1 year ago

That is working! Sorry, for whatever reason, I have to get used to the namespace.

Here's what I've got now; we're good to go!


conn = adbc_driver_snowflake.dbapi.connect(
    uri=format_uri(connection_params),
    db_kwargs={
        "adbc.snowflake.sql.db": connection_params.get("database"),
        "adbc.snowflake.sql.schema": connection_params.get("schema"),
        "adbc.snowflake.sql.role": connection_params.get("role")
    },
)

I'll likely fiddle with it more to switch things around, but this works great for now. I genuinely appreciate your help!

lidavidm commented 1 year ago

Cool! Yeah, the namespace is a little confusing; possibly we can make the Python bindings be 'smarter' about this

sfc-gh-twhite commented 1 year ago

I'm not sure if it would be worthwhile to mimic the Snowflake Python Connector's behavior with the args, as the URI stuff is always available, but not what most end users are doing to connect, I don't think.

Might be cool to fiddle around though do more conditional checking or something.