SQLAlchemy的事务中的错误不会返回正确的回溯(Python 2.7)

lim*_*to0 7 sqlalchemy traceback python-2.7

在我当前的模型User中,我有一个字段"name",它不能为null.

我尝试创建一个用户对象,并将其添加到Pyramid提供的DBSession并使用事务提交,就像这样.

with transaction.manager:
    u = models.User()
    models.DBSession.add(u)
Run Code Online (Sandbox Code Playgroud)

对于那些不使用金字塔的人,DBSession是:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Run Code Online (Sandbox Code Playgroud)

现在,在上面的交易中,我确实有一个验证问题 - 我需要为User分配一个名称,但我没有.但是,我没有收到错误告诉我"你需要为用户分配一个名字!",我得到了这个:

<ipython-input-5-47d9c0e393f7> in <module>()
      2     u = models.User()
----> 3     models.DBSession.add(u)
      4 

/home/user/Projects/env/local/lib/python2.7/site-packages/transaction-1.4.1-py2.7.egg/transaction/_manager.pyc in __exit__(self, t, v, tb)
    118     def __exit__(self, t, v, tb):
    119         if v is None:
--> 120             self.commit()
    121         else:
    122             self.abort()

/home/user/Projects/env/local/lib/python2.7/site-packages/transaction-1.4.1-py2.7.egg/transaction/_manager.pyc in commit(self)
    109         """ See ITransactionManager.
    110         """
--> 111         return self.get().commit()
    112 
    113     def abort(self):

/home/user/Projects/env/local/lib/python2.7/site-packages/transaction-1.4.1-py2.7.egg/transaction/_transaction.py in commit(self)
    276             tb = None
    277             try:
--> 278                 t, v, tb = self._saveAndGetCommitishError()
    279                 self._callAfterCommitHooks(status=False)
    280                 reraise(t, v, tb)

/home/user/Projects/env/local/lib/python2.7/site-packages/transaction-1.4.1-py2.7.egg/transaction/_transaction.py in _saveAndGetCommitishError(self)
    300             import pdb
    301             pdb.set_trace()
--> 302             traceback.print_stack(sys._getframe(1), None, ft)
    303             # Append the stack entries from here down to the exception.
    304             traceback.print_tb(tb, None, ft)

/usr/lib/python2.7/traceback.py in print_stack(f, limit, file)
    267         except ZeroDivisionError:
    268             f = sys.exc_info()[2].tb_frame.f_back
--> 269     print_list(extract_stack(f, limit), file)
    270 
    271 def format_stack(f=None, limit=None):

/usr/lib/python2.7/traceback.py in print_list(extracted_list, file)
     23                '  File "%s", line %d, in %s' % (filename,lineno,name))
     24         if line:
---> 25             _print(file, '    %s' % line.strip())
     26 
     27 def format_list(extracted_list):

/usr/lib/python2.7/traceback.py in _print(file, str, terminator)
     11 
     12 def _print(file, str='', terminator='\n'):
---> 13     file.write(str+terminator)
     14 
     15 

TypeError: 'unicode' does not have the buffer interface
Run Code Online (Sandbox Code Playgroud)

我发现手头的问题是,在某个地方,有一个python版本2对3不兼容,这里显示TypeError:'str'不支持缓冲区接口.我知道SQLAlchemy支持python 3+,所以这就是问题所在.

请注意,如果我正确执行了我的事务,则不会抛出任何错误.

有没有办法绕过这个问题而不必覆盖traceback.py中的代码?

Jas*_*son 2

您看到的错误不是(至少是直接)由 SQLAlchemy 引起的,而是由 SQLAlchemy、IPython 以及您尝试使用transaction. 如果您遵循这些工具的推荐用法,它就会消失。

免责声明:下面不是在 Pyramids 中使用作用域会话和 ZopeTransactionExtension 的推荐方法,但我想尽可能严格遵循您提供的代码。

将其放入文件中并从安装了 SQLAlchemy 的 virtualenv 运行它,您将看到来自 SQLAlchemy 的正确错误消息:

from sqlalchemy import types
from sqlalchemy import create_engine
from sqlalchemy.schema import Column
from zope.sqlalchemy import ZopeTransactionExtension
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session

Base = declarative_base()


class User(Base):
    __tablename__ = 'user'
    name = Column(types.String, primary_key=True)


def pretend_view(request):
    """Pretend view in a Pyramid application using pyramid_tm"""
    import transaction
    user = User()
    with transaction.manager:
        DBSession.add(user)
    return user

if __name__ == '__main__':
    engine = create_engine('sqlite://')
    global DBSession
    DBSession = scoped_session(
        sessionmaker(extension=ZopeTransactionExtension()))
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    Base.metadata.create_all()
    #import IPython; IPython.embed()
    pretend_view("dummy request")
Run Code Online (Sandbox Code Playgroud)

生成此异常:sqlalchemy.exc.IntegrityError: (IntegrityError) NOT NULL constraint failed: user.name u'INSERT INTO user DEFAULT VALUES' ()

如果您启动 IPython 并运行假装_view,您将收到您提到的 unicode 错误。

正确使用pyramid_tm

现在,如果您想在 IPython 中看到正确的错误消息,请“正确”使用会话!

通常没有理由transaction在代码中显式使用;当视图自动返回时,pyramid_tm 将提交事务(假设没有引发异常)。这将是运行视图的正确方法,并且即使在 IPython 中也会生成正确的异常:

def pretend_view(request):
    """Pretend view in a Pyramid application using pyramid_tm"""
    session = DBSession()  # You're using a sessionmaker, so you should make a session!
    user = User()
    session.add(user)
    session.flush()
    return user
Run Code Online (Sandbox Code Playgroud)

如果您确实想从视图内提交事务:

def pretend_view(request):
    """Pretend view in a Pyramid application using pyramid_tm"""
    session = DBSession()
    user = User()
    session.add(user)
    session.flush()
    import transaction
    transaction.commit()
    return user
Run Code Online (Sandbox Code Playgroud)

其他资源

SQLAlchemy-Pyramid 食谱:http://docs.pylonsproject.org/projects/pyramid/en/latest/tutorials/wiki2/index.html#bfg-sql-wiki-tutorial

Pyramid_tm 文档:http://pyramid-tm.readthedocs.org/en/latest/