Goles Goles - 27 days ago 6
Python Question

Crash: Method seems to take 3 arguments but only two were passed

I'm trying to use a Unique Object 'mixin' in my SQL Alchemy project. However, I'm clearly doing something incorrectly because my App is crashing with the following Python error.

Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 588, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/home/user/proj/dir/a/pipelines.py", line 26, in process_item
deck = self.extract_deck(item['md'], item['sb'], current_session)
File "/home/user/proj/dir/a/pipelines.py", line 62, in extract_deck
card = Card.as_unique(session, name=name)
File "/home/user/proj/dir/unique_mixin.py", line 39, in as_unique
arg, kw)
File "/home/user/proj/dir/unique_mixin.py", line 9, in _unique
key = (cls, hashfunc(*arg, **kw))
TypeError: unique_hash() takes exactly 3 arguments (2 given)


Seems like I'm passing less parameters than expected to the
unique_hash
method... but I don't know exactly where the problem lies.

Here's the code I'm using for Uniqueness. It defines a dictionary cache for a given SQLAlchemy Model.

def _unique(session, cls, hashfunc, queryfunc, constructor, arg, kw):
cache = getattr(session, '_unique_cache', None)
if cache is None:
session._unique_cache = cache = {}

key = (cls, hashfunc(*arg, **kw))
if key in cache:
return cache[key]
else:
with session.no_autoflush:
q = session.query(cls)
q = queryfunc(q, *arg, **kw)
obj = q.first()
if not obj:
obj = constructor(*arg, **kw)
session.add(obj)
cache[key] = obj
return obj

class UniqueMixin(object):
@classmethod
def unique_hash(cls, *arg, **kw):
raise NotImplementedError()

@classmethod
def unique_filter(cls, query, *arg, **kw):
raise NotImplementedError()

@classmethod
def as_unique(cls, session, *arg, **kw):
return _unique(session,
cls,
cls.unique_hash,
cls.unique_filter,
cls,
arg, kw)


Here's how my Card Model inherits the functionality.

class Card(UniqueMixin, Base):
__tablename__ = 'cards'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
cards_deck = relationship("DeckCardCount", back_populates='card', cascade='all, delete-orphan')

# For uniqueness
@classmethod
def unique_hash(cls, query, name):
return name

@classmethod
def unique_filter(cls, query, name):
return query.filter(Clard.name == name)


Here's how I'm trying to query a unique Card.

name = 'Some Unique Name'
card = Card.as_unique(session, name=name)

Answer

You're not passing query to unique_hash. Also note that session is not part of your arg since it was specified separately in the function def. So only one parameter name via kw is passed to unique_hash.

Considering that query is not being used in the unique_hash function, you can fix this by simply removing it, or making it obscure by using *arg:

@classmethod
def unique_hash(cls, *arg, name=None):
    return name