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

Python 2.7 SQLAlchemy中的错误';s事务不返回正确的回溯(Python 2.7),python-2.7,sqlalchemy,traceback,Python 2.7,Sqlalchemy,Traceback,在我当前的模型用户中,我有一个字段“name”,它不能为null 我尝试创建一个用户对象,并将其添加到Pyramid提供的DBSession中,然后将其与事务一起提交,如下所示 with transaction.manager: u = models.User() models.DBSession.add(u) 对于不使用金字塔的用户,DBSession是: DBSession = scoped_session(sessionmaker(extension=ZopeTransa

在我当前的模型用户中,我有一个字段“name”,它不能为null

我尝试创建一个用户对象,并将其添加到Pyramid提供的DBSession中,然后将其与事务一起提交,如下所示

with transaction.manager:
    u = models.User()
    models.DBSession.add(u)
对于不使用金字塔的用户,DBSession是:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
现在,在我上面的事务中,我确实有一个验证问题——我需要为用户分配一个名称,但我没有。但是,我得到的不是一个错误,告诉我“您需要为您的用户分配一个名称!”,而是:

<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
() 2 u=型号。用户() ---->3.DBSession.add模型(u) 4. /home/user/Projects/env/local/lib/python2.7/site-packages/transaction-1.4.1-py2.7.egg/transaction//u manager.pyc in\uuuuu exit\uuuu(self、t、v、tb) 118 def出口(自身、t、v、tb): 119如果v为无: -->120 self.commit() 121.其他: 122自我中止() /home/user/Projects/env/local/lib/python2.7/site-packages/transaction-1.4.1-py2.7.egg/transaction//u manager.pyc in commit(self) 109“请参阅ITransactionManager。 110 """ -->111返回self.get().commit() 112 113 def中止(自身): /home/user/Projects/env/local/lib/python2.7/site-packages/transaction-1.4.1-py2.7.egg/transaction//u transaction.py in commit(self) 276 tb=无 277尝试: -->278 t,v,tb=自我.\u saveandgetcommissionherror() 279 self.\u callAfterCommitHooks(状态=False) 280重调(t、v、tb) /home/user/Projects/env/local/lib/python2.7/site-packages/transaction-1.4.1-py2.7.egg/transaction//u transaction.py in\u saveandgetcommitiserror(self) 300进口pdb 301 pdb.set_trace() -->302回溯打印堆栈(系统获取帧(1),无,英尺) 303#将堆栈条目从这里向下附加到异常。 304回溯。打印\u tb(tb,无,英尺) /打印堆栈中的usr/lib/python2.7/traceback.py(f,limit,file) 267除零误差外: 268 f=sys.exc_info()[2].tb_frame.f_back -->269打印列表(提取堆栈(f,限制),文件) 270 271 def格式_堆栈(f=None,limit=None): /打印列表中的usr/lib/python2.7/traceback.py(提取列表,文件) 23'文件“%s”,第%d行,位于%s%%(文件名,行号,名称)) 24如果行: --->25_打印(文件“%s”%line.strip()) 26 27 def格式列表(提取列表): /打印中的usr/lib/python2.7/traceback.py(文件、str、终止符) 11 12 def_打印(文件,str='',terminator='\n'): --->13文件写入(str+终止符) 14 15 TypeError:“unicode”没有缓冲区接口 我发现眼前的问题是,在某个地方,存在python版本2与3的不兼容性,如图所示。我知道SQLAlchemy支持Python3+,所以这就是问题的根源

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


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

您看到的错误不是(至少是直接)由SQLAlchemy造成的,而是由SQLAlchemy、IPython和您尝试使用
事务的方式组合而成的。如果您遵循这些工具的推荐用法,它将消失

免责声明:下面不是在金字塔中使用作用域会话和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")
生成此异常:
sqlalchemy.exc.IntegrityError:(IntegrityError)非空约束失败:user.name u'INSERT INTO user DEFAULT VALUES'()

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

正确使用pyramid_tm

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

通常没有理由在代码中明确使用
事务
;当视图自动返回时(假设没有引发异常),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
如果确实要从视图中提交事务:

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
其他资源

SQLAlchemy金字塔食谱:


pyramid_tm文档:

您能提供完整的代码来重现错误吗?我不确定您还需要看到什么。用户模型只是有几个SQLAlchemy列,它看起来与无法正确处理错误无关(这发生在我尝试过的所有模型上,但仅当尝试提交()时,某些列的条目无效)你能提供一个最小的代码和一个需求文件来在一个新的virtualenv中重现错误吗?哇,我已经很久没有写这个问题了。我们在代码中不使用事务(或者,如果我们使用了事务,在了解中兴通讯的工作原理之前,最多需要一两天),但当数据需要在pshell/ipython中进行操作时,我们会使用事务。我们当然没有在任何视图中使用事务。当我们确实需要在ipython中使用transaction时,我们现在通常在transaction.manager上使用transaction.commit(),并且从那时起错误消息就没有出现任何问题。