2013-08-20 21 views
7

Trong mô hình hiện tại của tôi, tôi có một "tên" trường không thể rỗng.Lỗi trong giao dịch của SQLAlchemy không trả về traceback thích hợp (Python 2.7)

Tôi thử tạo đối tượng người dùng và thêm đối tượng đó vào DBSession do Pyramid cung cấp và gửi nó bằng giao dịch, như vậy.

with transaction.manager: 
    u = models.User() 
    models.DBSession.add(u) 

Đối với những người không sử dụng kim tự tháp, DBSession là:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) 

Bây giờ, trong giao dịch của tôi ở trên, tôi có một vấn đề xác nhận - Tôi cần phải gán một tên cho tài khoản, nhưng Tôi đã không. Tuy nhiên, thay vì nhận được một lỗi nói với tôi "Bạn cần phải gán người dùng của bạn một tên!", Tôi có được điều này:

<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 

tôi đã tìm thấy các vấn đề trong tầm tay là, ở đâu đó, có một phiên bản python 2 so với 3 không tương thích, được hiển thị ở đây TypeError: 'str' does not support the buffer interface. Tôi biết SQLAlchemy hỗ trợ python 3+, và vì vậy đó là nơi mà vấn đề có thể đến từ đó.

Lưu ý rằng nếu tôi thực hiện giao dịch của mình một cách chính xác, sẽ không có lỗi nào được đưa ra.

Có cách nào để giải quyết vấn đề này mà không phải ghi đè mã trong traceback.py không?

+0

Bạn có thể cung cấp mã hoàn chỉnh để tạo lại lỗi không? – javex

+0

Tôi không chắc bạn cần xem điều gì khác. Mô hình User chỉ đơn giản là có một vài cột SQLAlchemy và có vẻ như không liên quan đến việc không thể xử lý các lỗi một cách chính xác (điều này xảy ra với tất cả các mô hình mà tôi đã thử, nhưng chỉ khi cố gắng commit() với các mục không hợp lệ cho các cột nhất định) – limasxgoesto0

+2

Bạn có thể cung cấp mã tối thiểu và tệp yêu cầu để tạo lại lỗi trong virtualenv mới không? –

Trả lời

2

Lỗi bạn nhìn thấy không phải là (ít nhất là trực tiếp) do SQLAlchemy gây ra, mà thay vào đó là do sự kết hợp của SQLAlchemy, IPython và cách bạn đang cố sử dụng transaction. Nó sẽ biến mất nếu bạn làm theo việc sử dụng các công cụ này.

Tuyên bố từ chối: Dưới đây không phải là cách được khuyến nghị để sử dụng phiên scoped và ZopeTransactionExtension trong Kim tự tháp, nhưng tôi muốn gắn bó chặt chẽ với mã được cung cấp nhất có thể.

Đặt điều này trong một tập tin và chạy nó từ một virtualenv với SQLAlchemy cài đặt và bạn sẽ thấy thông báo lỗi đúng từ 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") 

Tạo ngoại lệ này: sqlalchemy.exc.IntegrityError: (IntegrityError) NOT NULL constraint failed: user.name u'INSERT INTO user DEFAULT VALUES'()

Nếu bạn cháy lên IPython thay vào đó và chạy pretend_view, bạn sẽ nhận được lỗi unicode mà bạn đã đề cập.

sử dụng đúng cách pyramid_tm

Bây giờ, nếu bạn muốn xem các thông báo lỗi chính xác trong IPython, sử dụng phiên "đúng"!

Thường không có lý do gì để sử dụng transaction một cách rõ ràng trong mã của bạn; pyramid_tm sẽ cam kết giao dịch khi khung nhìn trả về tự động (giả sử không có ngoại lệ nào được nâng lên).Đây sẽ là cách thích hợp để chạy xem, và sẽ tạo ra ngoại lệ chính xác ngay cả từ bên trong 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 

nếu bạn thực sự muốn cam kết giao dịch từ bên trong xem:

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 

Tài nguyên khác

SQLAlchemy-Pyramid sách dạy nấu ăn: http://docs.pylonsproject.org/projects/pyramid/en/latest/tutorials/wiki2/index.html#bfg-sql-wiki-tutorial

pyramid_tm d ocumentation: http://pyramid-tm.readthedocs.org/en/latest/

+0

Ồ, đã lâu rồi tôi mới viết câu hỏi này. Chúng tôi không sử dụng giao dịch trong mã của chúng tôi (hoặc nếu chúng tôi đã làm, nó đã được một hoặc hai ngày, trước khi tìm hiểu cách ZTE hoạt động), nhưng chúng tôi sử dụng nó khi dữ liệu cần phải được thao tác trong pshell/ipython. Chúng tôi chắc chắn không sử dụng giao dịch trong bất kỳ quan điểm nào của chúng tôi. Khi chúng ta cần sử dụng giao dịch trong ipython, bây giờ chúng ta thường sử dụng transaction.commit() trên transaction.manager, và các thông báo lỗi vẫn chưa đưa ra bất kỳ rắc rối nào kể từ đó. – limasxgoesto0

Các vấn đề liên quan