【问题标题】:Cannot import pyodbc on Mac无法在 Mac 上导入 pyodbc
【发布时间】:2016-04-20 15:41:08
【问题描述】:

我无法在我的 Macbook Pro(运行 Mac OS X 10.10.5)和 python 版本 2.7.10 上导入 pyodbc。我用pip 得到它,我有最新版本(3.0.10)。它给了我以下错误:

$ python
Python 2.7.10 (default, Jul 14 2015, 19:46:27) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyodbc
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: dlopen(/Library/Python/2.7/site-packages/pyodbc.so, 2): Symbol not found: _SQLAllocHandle
  Referenced from: /Library/Python/2.7/site-packages/pyodbc.so
  Expected in: flat namespace
 in /Library/Python/2.7/site-packages/pyodbc.so

在过去的几个月里,我尝试了几件事,但都无济于事,包括自己构建它(以及(重新)安装 iodbcunixodbc)。

其中一件奇怪的事情是,我尝试使用的其他 python 数据库包(例如 sqlalchemy、pypyodbc 等)都没有出于各种和类似的原因而工作。这让我怀疑我的 ODBC 驱动程序或库存在一些潜在问题,但我不知道如何诊断它。

我在共享代码环境中工作,团队其他成员通过 Windows 使用 pyodbc,我真的现在需要它来工作。任何帮助或建议将不胜感激!


**在回复 mauro 的回答时添加了更多详细信息。请注意,下面的第二次更新会改变一些事情。 **

这里有一些我应该在原始问题中包含的更多细节。

首先,这是 mauro 在我的机器上询问的命令的结果。

$ odbc_config --version
2.3.2
$ odbc_config --libs
-L/usr/local/Cellar/unixodbc/2.3.2_1/lib -lodbc
$ odbc_config --odbcini
/usr/local/Cellar/unixodbc/2.3.2_1/etc/odbc.ini
$ odbc_config --odbcinstini
/usr/local/Cellar/unixodbc/2.3.2_1/etc/odbcinst.ini

我对“酒窖”部分持怀疑态度,因此我查看了 mauro 答案中的路径,它们似乎都指向酒窖(自制?):

$ ls -al /usr/local/etc/*odbc*
lrwxr-xr-x  1 *****  admin  39 17 Aug 16:57 /usr/local/etc/odbc.ini@ -> ../Cellar/unixodbc/2.3.2_1/etc/odbc.ini
lrwxr-xr-x  1 *****  admin  43 17 Aug 16:57 /usr/local/etc/odbcinst.ini@ -> ../Cellar/unixodbc/2.3.2_1/etc/odbcinst.ini

$ ls -al /usr/local/etc/odbc*
lrwxr-xr-x  1 *****  admin  39 17 Aug 16:57 /usr/local/etc/odbc.ini@ -> ../Cellar/unixodbc/2.3.2_1/etc/odbc.ini
lrwxr-xr-x  1 *****  admin  43 17 Aug 16:57 /usr/local/etc/odbcinst.ini@ -> ../Cellar/unixodbc/2.3.2_1/etc/odbcinst.ini
1395:Stephens-BlueDot-MacBook-Pro:~/BlueDot/Code/Data Processing Tools} ls -al /usr/local/etc/*odbc*
lrwxr-xr-x  1 *****  admin  39 17 Aug 16:57 /usr/local/etc/odbc.ini@ -> ../Cellar/unixodbc/2.3.2_1/etc/odbc.ini
lrwxr-xr-x  1 *****  admin  43 17 Aug 16:57 /usr/local/etc/odbcinst.ini@ -> ../Cellar/unixodbc/2.3.2_1/etc/odbcinst.ini
1396:Stephens-BlueDot-MacBook-Pro:~/BlueDot/Code/Data Processing Tools} ls -al /usr/local/lib/*odbc*
lrwxr-xr-x  1 *****  admin  46 17 Aug 16:57 /usr/local/lib/libodbc.2.dylib@ -> ../Cellar/unixodbc/2.3.2_1/lib/libodbc.2.dylib
lrwxr-xr-x  1 *****  admin  44 17 Aug 16:57 /usr/local/lib/libodbc.dylib@ -> ../Cellar/unixodbc/2.3.2_1/lib/libodbc.dylib
lrwxr-xr-x  1 *****  admin  48 17 Aug 16:57 /usr/local/lib/libodbccr.2.dylib@ -> ../Cellar/unixodbc/2.3.2_1/lib/libodbccr.2.dylib
lrwxr-xr-x  1 *****  admin  46 17 Aug 16:57 /usr/local/lib/libodbccr.dylib@ -> ../Cellar/unixodbc/2.3.2_1/lib/libodbccr.dylib
lrwxr-xr-x  1 *****  admin  50 17 Aug 16:57 /usr/local/lib/libodbcinst.2.dylib@ -> ../Cellar/unixodbc/2.3.2_1/lib/libodbcinst.2.dylib
lrwxr-xr-x  1 *****  admin  48 17 Aug 16:57 /usr/local/lib/libodbcinst.dylib@ -> ../Cellar/unixodbc/2.3.2_1/lib/libodbcinst.dylib
lrwxr-xr-x  1 *****  admin  45 17 Aug 16:59 /usr/local/lib/libtdsodbc.0.so@ -> ../Cellar/freetds/0.95.18/lib/libtdsodbc.0.so
lrwxr-xr-x  1 *****  admin  42 17 Aug 16:59 /usr/local/lib/libtdsodbc.a@ -> ../Cellar/freetds/0.95.18/lib/libtdsodbc.a
lrwxr-xr-x  1 *****  admin  43 17 Aug 16:59 /usr/local/lib/libtdsodbc.so@ -> ../Cellar/freetds/0.95.18/lib/libtdsodbc.so

/usr/local/lib/tdbcodbc1.0.0:
total 144
drwxr-xr-x   5 root  wheel    170 29 Mar  2013 ./
drwxrwxr-x  44 root  admin   1496 17 Aug 16:59 ../
-rwxr-xr-x   1 root  wheel  49796 29 Mar  2013 libtdbcodbc1.0.0.dylib*
-r--r--r--   1 root  wheel    245 29 Mar  2013 pkgIndex.tcl
-r--r--r--   1 root  wheel  15624 29 Mar  2013 tdbcodbc.tcl

我可以通过tsql(具体匿名)很好地连接到 DNS:

$ tsql -S servername.myserver.com -U me -P mypw -D testdb
locale is "en_CA.UTF-8"
locale charset is "UTF-8"
using default charset "UTF-8"
Setting testdb as default database in login packet
1> 

但是osqlisql 都给出了问题:

$ isql -v MyDSN me mypw
[S1000][unixODBC][FreeTDS][SQL Server]Unable to connect to data source
[01000][unixODBC][FreeTDS][SQL Server]Unknown host machine name.
[ISQL]ERROR: Could not SQLConnect

这个提供了最多的信息。它至少在我的~/.odbc.ini 文件中找到了 DSN 条目。

$ osql -S MyDSN -U ***** -P ***** 
checking shared odbc libraries linked to isql for default directories...
/usr/local/bin/osql: line 53: ldd: command not found
error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strings: can't open file:  (No such file or directory)
osql: problem: no potential directory strings in "/usr/local/bin/isql"
osql: advice: use "osql -I DIR" where DIR unixODBC\'s install prefix e.g. /usr/local
isql strings are:
checking odbc.ini files
    reading /Users/*****/.odbc.ini
[MyDSN] found in /Users/*****/.odbc.ini
found this section:
    [MyDSN]                                                                                                                
    Description         = testdb SQLServer DB
    Driver              = FreeTDS
    Trace               = Yes
    TraceFile           = /tmp/sql.log
    Database            = Places
    ServerName          = *****
    UserName            = *****
    Password            = *****
    Port                = 1433
    Protocol            = 7.2
    ReadOnly            = No
    RowVersioning       = No
    ShowSystemTables    = No
    ShowOidColumn       = No
    FakeOidIndex        = No
looking for driver for DSN [*****] in /Users/*****/.odbc.ini
  found driver line: "  Driver              = FreeTDS"
  driver "FreeTDS" found for [*****] in .odbc.ini
found driver named "FreeTDS"
"FreeTDS" is not an executable file
looking for entry named [FreeTDS] in /odbcinst.ini
grep: /odbcinst.ini: No such file or directory

我不确定如何解决isql 报告的问题,但这似乎表明我对 odbc 的配置有误。不幸的是,很抱歉我不知道/确切地记得我做了什么才能做到这一点 - 几周来我一直在认真地尝试与此相关的各种事情。


在 mauro 的 cmets 之后的第二次更新。

我已经取得了一些进展。我重新安装了 unixODBC 和 freeTDS(直接从 http://www.unixodbc.org/http://www.freetds.org/ 而不是使用自制软件),然后我的 odbc_config 命令的输出与 mauro 的输出相匹配。

在尝试了一些路径之后,我能够同时获得 osqlisql 以成功连接到我的 SQL Server 实例。 (我发现之前失败的一个原因是因为我组织中的 IT 部门在 LAN 上阻止了所有到端口 1433 的流量。当我切换到 Wifi 时,就像我的 Windows 同事一样,它起作用了。)我认为这个进步很大!

但是,当我再次尝试从 python 中导入 pyodbc 时,我得到了与开始时完全相同的错误消息。叹。所以任何其他想法仍然会受到赞赏!

【问题讨论】:

    标签: python macos python-2.7 odbc pyodbc


    【解决方案1】:

    首先,感谢您对 @mauro 的帮助和坚持不懈的建议。

    经过几个月的头撞墙后,昨晚我终于可以让它工作了!

    在这里,我概述了一些(对我而言)关键的事情,希望它们对与我一样处于困境中的其他人有用。

    背景。不久前(一个多月),我阅读并尝试做here 建议的事情。虽然我不清楚当时我尝试过的所有操作,但这让我让tsql 正常工作,而且我认为我安装了unixODBCfreeTDS 的Homebrew 版本。

    从我提出上述问题开始,以下是我尝试过的一些似乎产生了影响的事情。 (我不确定哪些事情是最重要的,所以我将所有内容都包括在内。)第 1 点和第 2 点已在上面进行了描述,因此我将不再赘述。

    我。我从他们的项目网站重新安装了unixODBCfreeTDS

    二。我发现我的 LAN 上的 1433 端口被阻止了,所以我切换到没有被阻止的 WiFi。

    这两件事让我能够让isqlosql 工作。

    三。由于类似于动态链接错误的原因,pyodbc 无法在 python 中导入。我尝试使用dl.open()ctype.cdll.LoadLibrary() 直接加载/usr/local/lib/libodbc.dylib。在这两种情况下,我都有一个错误告诉我:

    dl.error: dlopen(libodbc.dylib, 6): no suitable image found.  Did find:
        /usr/local/lib/libodbc.dylib: mach-o, but wrong architecture
    

    经过一番挖掘,他带领我unixODBC 重新编译为 32 位而不是 64 位,如下所示:

    sudo ./configure CFLAGS="-m32 -arch i386 -O2" LDFLAGS="-m32 -arch i386" CXXFLAGS="-m32 -arch i386"
    sudo make 
    sudo make install
    

    那时,我能够使用dl.open() 显式加载libodbc.dylib 并且最后 让pyodbc 导入!!

    四。不幸的是,如果没有通过dl.open() 显式加载,导入仍然失败。这导致我玩我的LD_LIBRARY_PATH(如建议的here),但似乎还没有任何效果。所以我仍然坚持使用dl.open() hack。

    此外,当我尝试连接到数据源时,它仍然没有工作,与freeTDS 驱动程序有关。这最终导致我进行了以下“有效”的破解:

    import sys
    if (sys.platform == 'darwin'):
        import dl
        _lib1 = dl.open("libodbc.dylib")                      # Found in /usr/local/lib
        _lib2 = dl.open("/opt/local/lib/libtdsodbc.so")
    import pyodbc
    

    请注意,必须使用全局变量 _lib1_lib2 才能使其工作(我认为是为了保持加载内容)。

    在这一点上,一切似乎都运行良好,我可以使用pyodbc!!


    在此过程中我还尝试了一些其他方法,但我不清楚它们是否有帮助。

    • 我还尝试在 32 位模式下编译 freeTDS,类似于我为 unixODBC 所做的,但我不确定这是否有效。

    • 我从 github 存储库下载、构建和安装了 pyodbc,而不是使用 pip。 (它与pip 提供的版本相同——3.0.10。)

    • 根据评论 #10 here,我在 setup.pydarwin 案例中添加了两行 pyodbc 源下载(如下)并重新运行 python.py setup.py build install

    喜欢:

    elif sys.platform == 'darwin':                                                                                        
        # The latest versions of OS X no longer ship with iodbc.  Assume
        # unixODBC for now.
        settings['libraries'].append('odbc')
        settings['include_dirs'] = ['/opt/local/include']              # Added this line
        settings['library_dirs'] = ['/opt/local/lib']                  # Added this line
    
        # Python functions take a lot of 'char *' that really should be const.  gcc complains about this *a lot*
        settings['extra_compile_args'].extend([
            '-Wno-write-strings',
            '-Wno-deprecated-declarations'
        ])
    
        # Apple has decided they won't maintain the iODBC system in OS/X and has added deprecation warnings in 10.8.
        # For now target 10.7 to eliminate the warnings.
        settings['define_macros'].append( ('MAC_OS_X_VERSION_10_7',) )
    
        settings['include_dirs'] = ['/opt/local/include']
        settings['library_dirs'] = ['/opt/local/lib']
    
    • 全部完成后,我检查了一下,我还能够使用dl.open() hacks 导入和使用pypyodbc 而不。我不确定是否需要上述所有步骤才能发生这种情况。我怀疑主要问题是库的 32 位和 64 位版本。

    最后,虽然这与我无法导入 pyodbc 的原因无关,但我将添加一条关于导致我损失近一个小时的内容的注释。在某些时候,我试图遵循this site 的(非常有用的)说明。但是后来发现作者展示的非DSN连接字符串不起作用。相反,我不得不使用 FreeTDS 连接属性shown here 来让事情正常工作。例如:

    "DRIVER=FreeTDS;Server=*****;Port=1433;TDS_Version=7.2;Database=*****;UID=*****;PWD=*****"
    

    虽然现在大部分情况都对我有用,但我应该提一下,对于我的一些查询游标,我现在有时也会收到以下错误,但我认为它与上述任何一项都无关. (相反,我怀疑连接上存在某种“超时”问题。...)

      ...
        for row in cursor:
      File "/Library/Python/2.7/site-packages/pypyodbc.py", line 1920, in next
        row = self.fetchone()
      File "/Library/Python/2.7/site-packages/pypyodbc.py", line 1914, in fetchone
        check_success(self, ret)
      File "/Library/Python/2.7/site-packages/pypyodbc.py", line 986, in check_success
        ctrl_err(SQL_HANDLE_STMT, ODBC_obj.stmt_h, ret, ODBC_obj.ansi)
      File "/Library/Python/2.7/site-packages/pypyodbc.py", line 966, in ctrl_err
        raise DatabaseError(state,err_text)
    pypyodbc.DatabaseError: (u'08S01', u'[08S01] [FreeTDS][SQL Server]Bad token from the server: Datastream processing out of sync')
    Exception pypyodbc.DatabaseError: DatabaseError(u'08S01', u'[08S01] [FreeTDS][SQL Server]Write to the server failed') in <bound method Connection.__del__ of <pypyodbc.Connection instance at 0x60d5a8>> ignored
    

    总之,我认为至少有 3 个,如果不是 4 个,我不能在 python 中使用pyodbc 的原因。主要的两个与 unixODBC 的 32 位和 64 位编译以及一些我仍然不太了解的库导入路径问题有关。

    祝所有必须努力完成这一切的人好运!

    【讨论】:

    • 嗨 Turix,我正在通过硬设置 _lib1 和 _lib2 来尝试您的方法。但是,它一直说“ModuleNotFoundError:没有名为'dl'的模块”,即使我已经安装了很多次! :(
    • 嗨@alwaysaskingquestions。看起来 dl 模块已被弃用。他们有一条消息here 说要改用ctypes 模块。我还没有尝试过,但我想你会使用类似ctypes.CDLL() 的东西。祝你好运!!
    【解决方案2】:

    我同意...在我看来,首先要检查的是底层 ODBC 层。

    您说您已经从 Mac 上的源安装了 unixODBC(比如我)。所以使用 odbc_config 检查主要的 unixODBC 参数(你应该在/usr/local/bin 下拥有它):

    $ odbc_config --version
    2.3.4
    $ odbc_config --libs
    -L/usr/local/lib -lodbc
    $ odbc_config --odbcini
    /usr/local/etc/odbc.ini
    $ odbc_config --odbcinstini
    /usr/local/etc/odbcinst.ini
    

    然后——我猜——你已经为你的 ODBC 数据库创建了一个数据源。使用另一个 unixODBC 实用程序 (isql) 来检查您是否可以通过 ODBC 连接到您的数据库:

    $ sql <your_DSN> <your_DB_user> <your_DB_password> -v
    +---------------------------------------+
    | Connected!                            |
    |                                       |
    | sql-statement                         |
    | help [tablename]                      |
    | quit                                  |
    |                                       |
    +---------------------------------------+
    SQL> quit
    

    如果一切正常,则 unixODBC 层正常。

    更新

    嗯...你收到这条消息:

    ...
    checking odbc.ini files
    reading /Users/*****/.odbc.ini
    [MyDSN] found in /Users/*****/.odbc.ini
    ...
    

    但 unixODBC 报告的 odic.ini 位置不同:

    $ odbc_config --odbcini
    /usr/local/Cellar/unixodbc/2.3.2_1/etc/odbc.ini
    

    我还会检查 pyodbc 使用了哪些库。这里有我的:

    $ otool -L /Library/Python/2.7/site-packages/pyodbc.so
    /Library/Python/2.7/site-packages/pyodbc.so:
        /usr/local/lib/libodbc.2.dylib (compatibility version 3.0.0, current version 3.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
    

    如您所见,我的 pyodbc 使用安装在 /usr/local/lib 下的 libodbc。正是 odic_config 在我的案例中报告的位置。

    第二次更新

    进展顺利!所以,总结一下,目前的状态是:

    1. isql DSN USER PASSWORD 按预期工作
    2. import pyodbc 返回 _SQLAllocHandle 符号未找到。这意味着它没有找到正确的库
    3. otool -L ...pyodbc.so(与 2 中的路径相同。?)指向正确的库

    如果是这种情况,我会重新安装 pyodbc(我确实使用了 pip)。我听说旧版本无法找到正确的标头/库。现在isql 工作了...... pyodbc 也应该工作了。

    【讨论】:

    • 谢谢!我只是在我原来的问题中添加了更多细节。 (抱歉,我一开始就没有添加它们。)isqlosql 不起作用的事实似乎与我搞砸了 ODBC 安装/配置一致,但以前从未这样做过,我关于如何解决它的问题。
    • @Turix 请查看我的更新
    • 感谢您的更新。首先,otool 命令的输出与您的相同。至于 odbc.ini 的不同位置,我只是将我的~/.odbc.ini 文件的内容添加到/usr/local/etc/odbc.ini 以及地窖之一。没有帮助。不过,我认为这些问题比找到 DSN 更为根本。 (它甚至不能 import pyodbc...我什至还没到尝试连接到 DSN 的地步。)
    • @Turix 如何重新安装 unixODBC(最新版本是 2.3.4)并重新配置它。只有在 isql 启动并运行之后,我才会专注于 pyodbc
    • 感谢您的建议!我这样做了,最后让osqlisql 都连接到我的服务器。伟大的!不幸的是,导入 pyodbc 的问题仍然存在。 (我更新了上面的问题以反映这一点。)您还有其他建议吗? (再次感谢您帮助我走到这一步!)
    猜你喜欢
    • 1970-01-01
    • 2022-07-12
    • 1970-01-01
    • 2018-03-06
    • 2018-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-03
    相关资源
    最近更新 更多