Вопрос

Im trying to create "wrapper", which working with DB through SQLAlchemy ORM, but a issue with returning result: get error "Deferred instance has no attribute '__ getitem __'"

How i can fix this?

Source code: a) db_decorators.py

from twisted.internet import threads
from sqlalchemy import create_engine, pool
from sqlalchemy.orm import sessionmaker


def toThread(func):
    def wrapper(*args, **kwargs):
        return threads.deferToThread(func, *args, **kwargs)
    return wrapper

class DBDefer(object):
    def __init__(self, dsn, poolclass=pool.SingletonThreadPool):
        self.engine = create_engine(dsn, poolclass=poolclass)

    def __call__(self, func):
        @toThread
        def wrapper(*args, **kwargs):
            session = sessionmaker(bind=self.engine)()
            try:
                return func(session=session, *args, **kwargs)
            except:
                session.rollback()
                raise
            finally:
                session.close()
         return wrapper    

b) connector.py

import sqlalchemy
from twisted.internet.defer import Deferred
from db_decorators import DBDefer
from tables import Users

dbdefer = DBDefer('postgresql://test:test@localhost/testdb')

@dbdefer
def find_user_by_login(user_login, session=None):
    return session.execute(sqlalchemy.select([Users]).where(Users.name == user_login)).fetchone()


class DB_API(object):

    def find_user_by_login(self, user_login):
        d = Deferred()
        def _gotResult(user):
            if user is None:
                d.errback('No such user')
            else:
                d.callback(dict(user))
            return user
        find_user_by_login(user_login).addCallbacks(_gotResult, d.errback)
        return d

c) somewhere in server.py (server on Twisted)

def authorization(self, data):
    """
        Checking user with DB
    """
    log.msg("[AUTH] User=%s trying to auth..." % data['user'])
    #session = self.Session()
    #result = session.execute(sqlalchemy.select([Users]).where(Users.name == data['user']))
    #result = result.fetchone()
    #session.close()

    result = self.db_api.find_user_by_login(data['user'])
    data, result_msg = commands.AUTH(result, data)
    log.msg(result_msg)
    return data

Traceback:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 88, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 73, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
--- <exception caught here> ---
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/posixbase.py", line 614, in _doReadOrWrite
    why = selectable.doRead()
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 215, in doRead
    return self._dataReceived(data)
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 221, in _dataReceived
    rval = self.protocol.dataReceived(data)
  File "/usr/local/lib/python2.7/dist-packages/twisted/protocols/tls.py", line 419, in dataReceived
    self._flushReceiveBIO()
  File "/usr/local/lib/python2.7/dist-packages/twisted/protocols/tls.py", line 389, in _flushReceiveBIO
    ProtocolWrapper.dataReceived(self, bytes)
  File "/usr/local/lib/python2.7/dist-packages/twisted/protocols/policies.py", line 120, in dataReceived
    self.wrappedProtocol.dataReceived(data)
  File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/websocket.py", line 78, in dataReceived
    self._dataReceived(data)
  File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1270, in _dataReceived
    self.consumeData()
  File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1286, in consumeData
    while self.processData() and self.state != WebSocketProtocol.STATE_CLOSED:
  File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1445, in processData
    return self.processDataHybi()
  File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1758, in processDataHybi
    fr = self.onFrameEnd()
  File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1887, in onFrameEnd
    self._onMessageEnd()
  File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/websocket.py", line 107, in _onMessageEnd
    self.onMessageEnd()
  File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 734, in onMessageEnd
    self._onMessage(payload, self.message_is_binary)
  File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/websocket.py", line 110, in _onMessage
    self.onMessage(payload, isBinary)
  File "server.py", line 80, in onMessage
    json_data = self.commands_handlers['AUTH'](json_data)
  File "server.py", line 64, in authorization
    data, result_msg = commands.AUTH(result, data)
  File "/home/relrin/code/Helenae/helenae/commands.py", line 68, in AUTH
    if result['name'] == data['user']:
exceptions.AttributeError: Deferred instance has no attribute '__getitem__'
Это было полезно?

Решение

self.db_api.find_user_by_login(data['user']) returns a Deferred.

The code that uses it - data, result_msg = commands.AUTH(result, data) - disregards this fact and treats it like a result instead.

Half of the code in the question uses Deferred correctly. For example, this is correct:

find_user_by_login(user_login).addCallbacks(_gotResult, d.errback)

But the code where your error occurs doesn't try to define or set up any callbacks. It tries to use a Deferred as though it were a result - and it isn't.

You need to use addCallback et al more.

Also consider taking a look at alchimia if you want to use SQLAlchemy and Twisted together.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top