sqlalchemy 寻找服务器版本作为字符串,而不是类似字节的对象
sqlalchemy looking for server version as string, instead of bytes-like object
我不知道是什么突然导致了这个(我最近重新安装了 Anaconda 和我所有的 python 库,但我回到了和以前一样的版本),但是当 sqlalchemy 尝试连接到 SQL 服务器,它会失败,因为它会查找服务器版本并尝试对其进行 运行 字符串操作。
以下在我重新安装软件包之前没有问题。我会这样连接:
sqlalchemy_conn_string = 'mssql+pyodbc://myDSN'
sqlalchemy.create_engine(sqlalchemy_conn_string, module=pypyodbc)
然后它一直到一个名为 pyodbc.py 的文件并在此函数处失败:
def _get_server_version_info(self, connection):
try:
raw = connection.scalar("SELECT SERVERPROPERTY('ProductVersion')")
except exc.DBAPIError:
#...
else:
version= []
r = re.compile(r'[.\-]')
for n in r.split(raw): # culprit here
try:
version.append(int(n))
except ValueError:
version.append(n)
return tuple(version)
Out[1]: TypeError: cannot use a string pattern on a bytes-like object
那是因为在这一步,raw
不是一个可以拆分的字符串:
# from PyCharm's debugger window
raw = {bytes}b'13.0.5026.0'
此时,我不知道是否应该为 sqlalchemy and/or pypyodbc 提交错误报告,或者我是否可以自己解决这个问题。但我想要一个不涉及在我自己的机器上编辑 sqlalchemy 代码的解决方案(比如专门处理类似字节的对象),因为我们还有其他团队成员也将下载 vanilla sqlalchemy 和 pypyodbc 并且不会'没有信心编辑那个源代码。
我已确认 Python 3.6.4.
下的 pypyodbc 行为
print(pypyodbc.version) # 1.3.5
sql = """\
SELECT SERVERPROPERTY('ProductVersion')
"""
crsr.execute(sql)
x = crsr.fetchone()[0]
print(repr(x)) # b'12.0.5207.0'
请注意,SQLAlchemy 的 mssql+pyodbc
方言是为 pyodbc 编码的,而不是 pypyodbc,并且不能保证两者 100% 兼容。
显而易见的解决方案是改用 pyodbc。
更新:
检查您的 SQLAlchemy 版本。我刚刚查看了 mssql+pyodbc
dialect 的当前源代码,它
def _get_server_version_info(self, connection):
try:
# "Version of the instance of SQL Server, in the form
# of 'major.minor.build.revision'"
raw = connection.scalar(
"SELECT CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR)")
应该可以避免这个问题,即使在使用 pypyodbc 时也是如此。
如果您使用的是 SQLAlchemy 的最新生产版本(当前版本为 1.2.15),那么使用 1.3.0b1 版本可能会更好。
我不知道是什么突然导致了这个(我最近重新安装了 Anaconda 和我所有的 python 库,但我回到了和以前一样的版本),但是当 sqlalchemy 尝试连接到 SQL 服务器,它会失败,因为它会查找服务器版本并尝试对其进行 运行 字符串操作。
以下在我重新安装软件包之前没有问题。我会这样连接:
sqlalchemy_conn_string = 'mssql+pyodbc://myDSN'
sqlalchemy.create_engine(sqlalchemy_conn_string, module=pypyodbc)
然后它一直到一个名为 pyodbc.py 的文件并在此函数处失败:
def _get_server_version_info(self, connection):
try:
raw = connection.scalar("SELECT SERVERPROPERTY('ProductVersion')")
except exc.DBAPIError:
#...
else:
version= []
r = re.compile(r'[.\-]')
for n in r.split(raw): # culprit here
try:
version.append(int(n))
except ValueError:
version.append(n)
return tuple(version)
Out[1]: TypeError: cannot use a string pattern on a bytes-like object
那是因为在这一步,raw
不是一个可以拆分的字符串:
# from PyCharm's debugger window
raw = {bytes}b'13.0.5026.0'
此时,我不知道是否应该为 sqlalchemy and/or pypyodbc 提交错误报告,或者我是否可以自己解决这个问题。但我想要一个不涉及在我自己的机器上编辑 sqlalchemy 代码的解决方案(比如专门处理类似字节的对象),因为我们还有其他团队成员也将下载 vanilla sqlalchemy 和 pypyodbc 并且不会'没有信心编辑那个源代码。
我已确认 Python 3.6.4.
下的 pypyodbc 行为print(pypyodbc.version) # 1.3.5
sql = """\
SELECT SERVERPROPERTY('ProductVersion')
"""
crsr.execute(sql)
x = crsr.fetchone()[0]
print(repr(x)) # b'12.0.5207.0'
请注意,SQLAlchemy 的 mssql+pyodbc
方言是为 pyodbc 编码的,而不是 pypyodbc,并且不能保证两者 100% 兼容。
显而易见的解决方案是改用 pyodbc。
更新:
检查您的 SQLAlchemy 版本。我刚刚查看了 mssql+pyodbc
dialect 的当前源代码,它
def _get_server_version_info(self, connection):
try:
# "Version of the instance of SQL Server, in the form
# of 'major.minor.build.revision'"
raw = connection.scalar(
"SELECT CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR)")
应该可以避免这个问题,即使在使用 pypyodbc 时也是如此。
如果您使用的是 SQLAlchemy 的最新生产版本(当前版本为 1.2.15),那么使用 1.3.0b1 版本可能会更好。